Что означает этот список отличий в реальном коде? Определите массивы объектов типа char
, vector
, list
и string
со значением "Hello
", передайте его в функцию в качестве аргумента, напишите количество символов в передаваемой строке, попытайтесь сравнить его со строкой "Hello
" в функции (чтобы убедиться, что вы действительно передали строку "Hello
"), а затем сравните аргумент со строкой "Howdy
", чтобы увидеть, какое из этих слов появляется в словаре первым. Скопируйте аргумент в другую переменную того же типа.
ПОПРОБУЙТЕ
Выполните предыдущее задание ПОПРОБУЙТЕ для массива объектов типа int
, vector
и list
со значениями { 1
, 2
, 3
, 4
, 5
} .
20.7.1. Операции insert и erase
insert()
и erase()
), в векторе происходит перемещение остальных элементов; это может оказаться связано с неприемлемыми затратами, если вектор содержит большое количество элементов или элементы вектора сами являются крупными объектами. Однако слишком беспокоиться об этом не следует. Мы без заметных проблем считали полмиллиона значений с плавающей точкой в вектор, используя функцию push_back()
. Измерения подтвердили, что предварительное выделение памяти не приводит к заметным последствиям. Прежде чем вносить значительные изменения, стремясь к эффективности, проведите измерения (угадать степень эффективности кода трудно даже экспертам).
insert()
, erase()
, and push_back()
), не следует хранить итераторы или указатели на элементы вектора. Если элемент будет перемещен, ваш итератор или указатель будет установлен на неправильный элемент или вообще может не ссылаться на элемент вектора. В этом заключается принципиальное преимущество класса list
(и класса map
; см. раздел 21.6) над классом vector
. Если вам необходима коллекция крупных объектов или приходится ссылаться на объекты во многих частях программы, рассмотрите возможность использовать класс list
.
Сравним функции insert()
и erase()
в классах vector
и list
. Сначала рассмотрим пример, разработанный специально для того, чтобы продемонстрировать принципиальные моменты.
vector
++p; ++p; ++p; // устанавливаем итератор
// на 4-й элемент
vector
++q; // устанавливаем итератор
// на 5-й элемент
p = v.insert(p,99); // итератор p ссылается на вставленный элемент
Теперь итератор q
является неправильным. При увеличении размера вектора элементы могли быть перемещены в другое место. Если вектор v
имеет запас памяти, то он будет увеличен на том же самом месте, а итератор q
скорее всего будет ссылаться на элемент со значением 3
, а не на элемент со значением 4
, но не следует пытаться извлечь из этого какую-то выгоду.
p = v.erase(p); // итератор p ссылается на элемент,
// следующий за стертым
Иначе говоря, если за функцией insert()
следует функция erase()
, то содержание вектора не изменится, но итератор q
станет некорректным. Однако если между ними мы переместим все элементы вправо от точки вставки, то вполне возможно, что при увеличении размера вектора v
все элементы будут размещены в памяти заново.
Для сравнения мы проделали то же самое с объектом класса list
:
list
++p; ++p; ++p; // устанавливаем итератор
// на 4-й элемент
list
++q; // устанавливаем итератор
// на 5-й элемент
p = v.insert(p,99); // итератор р ссылается на вставленный элемент
Обратите внимание на то, что итератор q
по-прежнему ссылается на элемент, имеющий значение 4
.
p = v.erase(p); // итератор р ссылается на элемент, следующий
// за удаленным