Чтение онлайн

на главную - закладки

Жанры

Эффективное использование STL
Шрифт:

• чтобы эмулировать вставку в позицию, заданную итератором

ri
типа
reverse_iterator
, выполните вставку в позицию
r.base
. По отношению к операции вставки
ri
и
r.base
эквивалентны, но
r.base
в действительности представляет собой
iterator
, соответствующий
ri
.

Рассмотрим операцию удаления элемента. Вернемся к взаимосвязи между

ri
и исходным вектором (по состоянию на момент, предшествующий вставке значения 99):

Для

удаления элемента, на который указывает итератор
ri
, нельзя просто использовать
i
, поскольку этот итератор ссылается на другой элемент. Вместо этого нужно удалить элемент, предшествующий
i
. Заключение:

• чтобы эмулировать удаление в позиции, заданной итератором

ri
типа
reverse_iterator
, выполните удаление в позиции, предшествующей
ri.base
. По отношению к операции удаления
ri
и
ri.base
не эквивалентны, a
ri.base
не является объектом
iterator
, соответствующим
ri
.

Однако к коду стоит присмотреться повнимательнее, поскольку вас ждет сюрприз:

vector<int> v;

… // См. ранее. В вектор v заносятся

// числа 1-5

vector<int>::reverse_iterator ri = // Установить ri на элемент 3

 find(v.rbegin, v.rend, 3);

v.erase(--ri.base); // Попытка стирания в позиции.

// предшествующей ri-base:

// для вектора обычно

// не компилируется

Решение выглядит вполне нормально. Выражение

– -ri.base
правильно определяет элемент, предшествующий удаляемому. Более того, приведенный фрагмент будет нормально работать для всех стандартных контейнеров, за исключением
vector
и
string
. Наверное, он бы мог работать и для этих контейнеров, но во многих реализациях
vector
и
string
он не будет компилироваться. В таких реализациях типы
iterator
const_iterator
) реализованы в виде встроенных указателей, поэтому результатом вызова
i.base
является указатель. В соответствии с требованиями как C, так и C++ указатели, возвращаемые функциями, не могут модифицироваться, поэтому на таких платформах STL выражения типа
– -i.base
не компилируются. Чтобы удалить элемент в позиции, заданной итератором
reverse_iterator
, и при этом сохранить переносимость, необходимо избегать модификации возвращаемого значения
base
. Впрочем, это несложно. Если мы не можем уменьшить результат вызова
base
, значит, нужно увеличить
reverse_iterator
и после этого вызвать
base
!

… //См. ранее

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
никогда не пропускают символы при вводе и просто возвращают следующий символ из буфера.

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

Цветы сливы в золотой вазе, или Цзинь, Пин, Мэй

Ланьлинский насмешник
Старинная литература:
древневосточная литература
7.00
рейтинг книги
Цветы сливы в золотой вазе, или Цзинь, Пин, Мэй

Кодекс Охотника. Книга XIX

Винокуров Юрий
19. Кодекс Охотника
Фантастика:
фэнтези
5.00
рейтинг книги
Кодекс Охотника. Книга XIX

70 Рублей - 2. Здравствуй S-T-I-K-S

Кожевников Павел
Вселенная S-T-I-K-S
Фантастика:
боевая фантастика
постапокалипсис
5.00
рейтинг книги
70 Рублей - 2. Здравствуй S-T-I-K-S

Мастер 3

Чащин Валерий
3. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер 3

Лучше подавать холодным

Аберкромби Джо
4. Земной круг. Первый Закон
Фантастика:
фэнтези
8.45
рейтинг книги
Лучше подавать холодным

Имперец. Земли Итреи

Игнатов Михаил Павлович
11. Путь
Фантастика:
героическая фантастика
боевая фантастика
5.25
рейтинг книги
Имперец. Земли Итреи

Адвокат империи

Карелин Сергей Витальевич
1. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
фэнтези
5.75
рейтинг книги
Адвокат империи

Ваше Сиятельство 2

Моури Эрли
2. Ваше Сиятельство
Фантастика:
фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Ваше Сиятельство 2

Не грози Дубровскому!

Панарин Антон
1. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не грози Дубровскому!

Отмороженный 7.0

Гарцевич Евгений Александрович
7. Отмороженный
Фантастика:
рпг
аниме
5.00
рейтинг книги
Отмороженный 7.0

Лолита

Набоков Владимир Владимирович
Проза:
классическая проза
современная проза
8.05
рейтинг книги
Лолита

Энфис 5

Кронос Александр
5. Эрра
Фантастика:
героическая фантастика
рпг
аниме
5.00
рейтинг книги
Энфис 5

Опасная любовь командора

Муратова Ульяна
1. Проклятые луной
Фантастика:
фэнтези
5.00
рейтинг книги
Опасная любовь командора

Найди меня Шерхан

Тоцка Тала
3. Ямпольские-Демидовы
Любовные романы:
современные любовные романы
короткие любовные романы
7.70
рейтинг книги
Найди меня Шерхан