Вход/Регистрация
Эффективное использование STL
вернуться

Мейерс Скотт

Шрифт:

… //См. ранее

v.erase((++ri).base); // Удалить элемент, на который указывает ri;

// команда всегда компилируется

Такая методика работает во всех стандартных контейнерах и потому считается предпочтительным способом удаления элементов, определяемых итератором

reverse_iterator
.

Вероятно, вы уже поняли: говорить о том, что функция

base
класса
reverse_iterator
возвращает «соответствующий»
iterator
, не совсем правильно. В отношении вставки это действительно так, а в отношении удаления — нет. При преобразовании
reverse_iterator
в
iterator
важно знать, какие операции будут выполняться с полученным объектом
iterator
. Только в этом случае вы сможете определить, подойдет ли он для ваших целей.

Совет 29. Рассмотрите возможность использования istreambuf_iterator при посимвольном вводе

Предположим, вы хотите скопировать текстовый файл в объект

string
. На первый взгляд следующее решение выглядит вполне разумно:

ifstream inputFile("interestringData.txt");

string fileData(istream_iterator<char>(inputFile)), // Прочитать inputFile

 istream iterator<char>); // в fileData

Но вскоре выясняется, что приведенный синтаксис не копирует в строку пропуски (

whitespace
), входящие в файл. Это объясняется тем, что
istream_iterator
производит непосредственное чтение функциями
operator<<
, а эти функции по умолчанию не читают пропуски.

Чтобы сохранить пропуски, входящие в файл, достаточно включить режим чтения пропусков сбросом флага

skipws
для входного потока:

ifstream inputFile("interestingData.txt");

inputFile.unset(ios::skipws); // Включить режим

// чтения пропусков

// в inputFile

string fileData(istream_iterator<char>(inputFile)), // Прочитать inputFile

 istream_iterator<char>); // в fileData.

Теперь все символы

InputFile
копируются в
fileData
.

Кроме того, может выясниться, что копирование происходит не так быстро, как вам хотелось бы. Функции

operator<<
, от которых зависит работа
stream_iterator
, производят форматный ввод, а это означает, что каждый вызов сопровождается многочисленными служебными операциями. Они должны создать и уничтожить объекты
sentry
(специальные объекты потоков ввода-вывода, выполняющие начальные и завершающие операции при каждом вызове
operator<<
); они должны проверить состояние флагов, влияющих на их работу (таких, как
skpws
); они должны выполнить доскональную проверку ошибок чтения, а в случае обнаружения каких-либо проблем — проанализировать маску исключений потока и определить, нужно ли инициировать исключение. Все перечисленные операции действительно важны при форматном вводе, но если ваши потребности ограничиваются чтением следующего символа из входного потока, без них можно обойтись.

Более эффективное решение основано на использовании неприметного итератора

istreambuf_iterator
. Итераторы
istreambuf_iterator
работают аналогично
istream_iterator
, но если объекты
istream_iterator<char>
читают отдельные символы из входного потока оператором
<<
, то объекты
streambuf_iterator
обращаются прямо к буферу потока и непосредственно читают следующий символ (выражаясь точнее, объект
streambuf_iterator<char>
читает следующий символ из входного потока
s
вызовом
s.rdbuf ->sgetc
).

Перейти на использование

istreambuf_iterator
при чтении файла так просто, что даже программист Visual Basic сделает это со второй попытки:

ifstream inputFile("interestingData.txt");

string fileData(istreambuf_iterator<char>(inputFile)),

 istreambuf_iterator<char>0);

На этот раз сбрасывать флаг skpws не нужно, итераторы

streambuf_iterator
никогда не пропускают символы при вводе и просто возвращают следующий символ из буфера.

По сравнению с

istream_iterator
это происходит относительно быстро. В проведенных мною простейших тестах выигрыш по скорости достигал 40%, хотя в вашем случае цифры могут быть другими. Не удивляйтесь, если быстродействие будет расти со временем; итераторы
istreambuf_iterator
населяют один из заброшенных уголков STL, и авторы реализаций еще недостаточно позаботились об их оптимизации. Например, в моих примитивных тестах итераторы
istreambuf_iterator
одной из реализаций работали всего на 5% быстрее, чем
istream_iterator
. В таких реализациях остается широкий простор для оптимизации
istreambuf_iterator
.

Если вы планируете читать из потока по одному символу, не нуждаетесь в средствах форматирования ввода и следите за эффективностью выполняемых операций, три лишних символа на итератор — не такая уж дорогая цена за заметный рост быстродействия. При неформатном посимвольном вводе всегда рассматривайте возможность применения

sreambuf_iterator
.

Раз уж речь зашла о буферизованных итераторах, следует упомянуть и об использовании

ostreambuf_iterator
при неформатном посимвольном выводе. По сравнению с
ostream_iterator
итераторы
ostreambuf_iterator
обладают меньшими затратами (при меньших возможностях), поэтому обычно они превосходят их по эффективности.

  • Читать дальше
  • 1
  • ...
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: