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

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

Жанры

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

• Интервальное удаление. Интервальная форма erase существует в каждом стандартном контейнере, но типы возвращаемого значения отличаются для последовательных и ассоциативных контейнеров. В последовательных контейнерах используется следующий вариант сигнатуры:

iterator контейнер::erase(iterator begin, iterator end);

В ассоциативных контейнерах сигнатура выглядит так:

void контейнер::erase(iterator begin, iterator end);

Чем обусловлены различия? Утверждается, что в ассоциативных контейнерах возврат

итератора (для элемента, следующего за удаленным) привел бы к неприемлемому снижению быстродействия. Мне и многим другим это утверждение кажется сомнительным, но Стандарт есть Стандарт, а в нем сказано, что версии
erase
для последовательных и ассоциативных контейнеров обладают разными типами возвращаемого значения.

Многое из того, что говорилось в этом совете по поводу эффективности

insert
, относится и к
erase
. Интервальная форма
erase
также сокращает количество вызовов функций по сравнению с одноэлементной формой. При одноэлементном удалении элементы тоже сдвигаются на одну позицию к своему итоговой позиции, тогда как в интервальном варианте каждый элемент перемещается к итоговой позиции за одну операцию.

Но erase не присущ такой недостаток

insert
контейнеров
vector
и
string
, как многократные выделения памяти (конечно, для erase речь пойдет о многократном освобождении). Дело в том, что память, занимаемая
vector
и
string
, автоматически увеличивается для новых элементов, но при уменьшении количества элементов память не освобождается (в совете 17 рассказано о том, как уменьшить затраты освободившейся памяти в
vector
и
string
).

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

• Интервальное присваивание. Как упоминалось в самом начале совета, во всех последовательных контейнерах предусмотрена интервальная форма

assign
:

void контейнер::assign(InputIterator begin, InputIterator end);

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

Совет 6. Остерегайтесь странностей лексического разбора C++

Предположим, у вас имеется файл, в который записаны числа типа

int
, и вы хотите скопировать эти числа в контейнер
list
. На первый взгляд следующее решение выглядит вполне разумно:

ifstream dataFile("ints.dat");

list<int> data(istream_iterator<int>(dataFile), // Внимание! Эта строка

 istream_iterator<int>); // работает не так, как

// вы предполагали

Идея проста: передать пару

istream_iterator
интервальному конструктору
list
(совет 5), после чего скопировать числа из файла в список.

Программа будет компилироваться, но во время выполнения

она ничего не сделает. Она не прочитает данные из файла. Она даже не создаст список — а все потому, что вторая команда не объявляет список и не вызывает конструктор. Вместо этого она… Произойдет нечто настолько странное, что я даже не рискну прямо сказать об этом, потому что вы мне не поверите. Вместо этого я попробую объяснить суть дела постепенно, шаг за шагом. Надеюсь, вы сидите? Если нет — лучше поищите стул…

Начнем с азов. Следующая команда объявляет функцию

f
, которая получает
double
и возвращает
int
:

int f(double d);

То же самое происходит и в следующей строке. Круглые скобки вокруг имени параметра

d
не нужны, поэтому компилятор их игнорирует:

int f(double(d));// То же,- круглые скобки вокруг d игнорируются

Рассмотрим третий вариант объявления той же функции. В нем просто не указано имя параметра:

int f(double);// То же; имя параметра не указано

Вероятно, эти три формы объявления вам знакомы, хотя о возможности заключать имена параметров в скобки известно далеко не всем (до недавнего времени я о ней не знал).

Теперь рассмотрим еще три объявления функции. В первом объявляется функция

g
с параметром — указателем на функцию, которая вызывается без параметров и возвращает
double
:

int g(double (*pf)); // Функции g передается указатель на функцию

То же самое можно сформулировать и иначе. Единственное различие заключается в том, что

pf
объявляется в синтаксисе без указателей (допустимом как в C, так и в C++):

int g(double pf); // То же; pf неявно интерпретируется как указатель

Как обычно, имена параметров могут опускаться, поэтому возможен и третий вариант объявления

g
без указания имени
pf
:

int g(double);// То же: имя параметра не указано

Обратите внимание на различия между круглыми скобками вокруг имени параметра (например, параметра

d
во втором объявлении
f
) и стоящими отдельно (как в этом примере). Круглые скобки, в которые заключено имя параметра, игнорируются, а круглые скобки, стоящие отдельно, обозначают присутствие списка параметров; они сообщают о присутствии параметра, который является указателем на функцию.

После небольшой разминки с объявлениями

f
и
g
мы возвращаемся к фрагменту, с которого начинается этот совет. Ниже он приводится снова:

list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>);

Держитесь и постарайтесь не упасть. Перед вами объявление функции

data
, возвращающей тип
list<int>
. Функция
data
получает два параметра:

• Первый параметр,

dataFile
, относится к типу
istream_iterator<int>
. Лишние круглые скобки вокруг
dataFile
игнорируются.

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

Зубных дел мастер

Дроздов Анатолий Федорович
1. Зубных дел мастер
Фантастика:
научная фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Зубных дел мастер

Бывшие. Война в академии магии

Берг Александра
2. Измены
Любовные романы:
любовно-фантастические романы
7.00
рейтинг книги
Бывшие. Война в академии магии

Идеальный мир для Лекаря 7

Сапфир Олег
7. Лекарь
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 7

Возвышение Меркурия. Книга 3

Кронос Александр
3. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 3

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

Винокуров Юрий
10. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
6.25
рейтинг книги
Кодекс Охотника. Книга X

Хозяин Теней

Петров Максим Николаевич
1. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Хозяин Теней

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

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

Друд, или Человек в черном

Симмонс Дэн
Фантастика:
социально-философская фантастика
6.80
рейтинг книги
Друд, или Человек в черном

Волхв

Земляной Андрей Борисович
3. Волшебник
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волхв

Мастер Разума VII

Кронос Александр
7. Мастер Разума
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер Разума VII

Всемирная энциклопедия афоризмов. Собрание мудрости всех народов и времен

Агеева Елена А.
Документальная литература:
публицистика
5.40
рейтинг книги
Всемирная энциклопедия афоризмов. Собрание мудрости всех народов и времен

Сумеречный Стрелок 5

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

Морской волк. 1-я Трилогия

Савин Владислав
1. Морской волк
Фантастика:
альтернативная история
8.71
рейтинг книги
Морской волк. 1-я Трилогия

Прогрессор поневоле

Распопов Дмитрий Викторович
2. Фараон
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прогрессор поневоле