Читаем Программирование полностью

Что означает этот список отличий в реальном коде? Определите массивы объектов типа char, vector, list и string со значением "Hello", передайте его в функцию в качестве аргумента, напишите количество символов в передаваемой строке, попытайтесь сравнить его со строкой "Hello" в функции (чтобы убедиться, что вы действительно передали строку "Hello"), а затем сравните аргумент со строкой "Howdy", чтобы увидеть, какое из этих слов появляется в словаре первым. Скопируйте аргумент в другую переменную того же типа.

ПОПРОБУЙТЕ

Выполните предыдущее задание ПОПРОБУЙТЕ для массива объектов типа int, vector и list со значениями { 1, 2, 3, 4, 5 } . 

<p id="AutBody_Root384"><strong>20.7.1. Операции insert и erase</strong></p>

  В качестве контейнера по умолчанию используется стандартный класс vector. Он имеет большинство желательных свойств, поэтому альтернативу следует использовать только при необходимости. Его основной недостаток заключается в том, что при выполнении операций, характерных для списка (insert() и erase()), в векторе происходит перемещение остальных элементов; это может оказаться связано с неприемлемыми затратами, если вектор содержит большое количество элементов или элементы вектора сами являются крупными объектами. Однако слишком беспокоиться об этом не следует. Мы без заметных проблем считали полмиллиона значений с плавающей точкой в вектор, используя функцию push_back(). Измерения подтвердили, что предварительное выделение памяти не приводит к заметным последствиям. Прежде чем вносить значительные изменения, стремясь к эффективности, проведите измерения (угадать степень эффективности кода трудно даже экспертам).

  Как указывалось в разделе 20.6, перемещение элементов связано с логическим ограничением: выполняя операции, характерные для списков (такие как insert(), erase(), and push_back()), не следует хранить итераторы или указатели на элементы вектора. Если элемент будет перемещен, ваш итератор или указатель будет установлен на неправильный элемент или вообще может не ссылаться на элемент вектора. В этом заключается принципиальное преимущество класса list (и класса map; см. раздел 21.6) над классом vector. Если вам необходима коллекция крупных объектов или приходится ссылаться на объекты во многих частях программы, рассмотрите возможность использовать класс list.

Сравним функции insert() и erase() в классах vector и list. Сначала рассмотрим пример, разработанный специально для того, чтобы продемонстрировать принципиальные моменты.

vector::iterator p = v.begin();  // получаем вектор

++p; ++p; ++p;                        // устанавливаем итератор

                                      // на 4-й элемент

vector::iterator q = p;

++q;                                  // устанавливаем итератор

                                      // на 5-й элемент

p = v.insert(p,99); // итератор p ссылается на вставленный элемент

Теперь итератор q является неправильным. При увеличении размера вектора элементы могли быть перемещены в другое место. Если вектор v имеет запас памяти, то он будет увеличен на том же самом месте, а итератор q скорее всего будет ссылаться на элемент со значением 3, а не на элемент со значением 4, но не следует пытаться извлечь из этого какую-то выгоду.

p = v.erase(p); // итератор p ссылается на элемент,

                // следующий за стертым

Иначе говоря, если за функцией insert() следует функция erase(), то содержание вектора не изменится, но итератор q станет некорректным. Однако если между ними мы переместим все элементы вправо от точки вставки, то вполне возможно, что при увеличении размера вектора v все элементы будут размещены в памяти заново.

Для сравнения мы проделали то же самое с объектом класса list:

list::iterator p = v.begin(); // получаем список

++p; ++p; ++p;                     // устанавливаем итератор

                                   // на 4-й элемент

list::iterator q = p;

++q;                               // устанавливаем итератор

                                   // на 5-й элемент

p = v.insert(p,99); // итератор р ссылается на вставленный элемент

Обратите внимание на то, что итератор q по-прежнему ссылается на элемент, имеющий значение 4.

p = v.erase(p);  // итератор р ссылается на элемент, следующий

                 // за удаленным

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже