Использование резервирования или указание числа объектов по умолчанию в конструкторе помогает избежать ненужных перераспределений буфера, Это приводит к увеличению производительности, но также позволяет избежать и еще одной проблемы: каждый раз, когда происходит перераспределение буфера, все итераторы, имевшиеся на этот момент и указывающие на элементы, становятся недействительными.
Наконец, плохой идеей является вставка элементов в любое место, кроме конца вектора. Посмотрите на рис. 6.1. Так как vector— это просто массив с дополнительными прибамбасами, становится очевидно, почему следует добавлять элементы только в конец вектора. Объекты в vectorхранятся последовательно, так что при вставке элемента в любое место, кроме конца, скажем, по индексу n , объекты с n +1 до конца должны быть сдвинуты на один (в сторону конца) и освободить место для нового элемента. Сложность этой операции линейна, что означает, что она оказывается дорогостоящей даже для векторов скромного размера. Удаление элемента вектора имеет такой же эффект: оно означает, что все индексы больше n должны быть сдвинуты на один слот вверх. Если требуется возможность вставки и удаления в произвольном месте контейнера, вместо вектора следует использовать list.
Проблема
Требуется скопировать содержимое одного vectorв другой.
Решение
Имеется пара способов сделать это. Можно при создании vectorиспользовать конструктор копирования, а можно использовать метод assign. Пример 6.3 показывает оба этих способа.
Пример 6.3. Копирование содержимого vector
#include
#include
#include
#include
using namespace std;
// Вспомогательная функция для печати содержимого вектора
template
void vecPrint (const vector& vec) {
cout << "{";
for (typename vector::const_iterator p = vec.begin();
p != vec.end(); ++p) {
cout << "{" << *p << "} ";
}
cout << "}" << endl;
}
int main() {
vector vec(5);
string foo[] = {"My", "way", "or", "the", "highway"};
vec[0] = "Today";
vec[1] = "is";
vec[2] = "a";
vec[3] = "new";
vec[4] = "day";
vector vec2(vec);
vecPrint(vec2);
vec.at(0) = "Tomorrow";
vec2.assign(vec.begin(), vec.end()); // Копирование каждого элемента
vecPrint(vec2); // с помощью присвоения
vec2.assign(&foo[0], &foo[5]); // Присвоение работает для всего, что
vecPrint(vec2); // ведет себя как итератор
vector::iterator p;
p = find(vec.begin(), vec.end(), "new");
vec2.assign(vec.begin(), p); // Копирование подмножества полного диапазона
vecPrint(vec2); // vec
}
Обсуждение
Копирование vectorпросто. Имеется два способа сделать это. Можно скопировать один vectorв другой с помощью конструктора копирования, как и любой другой объект, а можно использовать метод assign. О конструкторе копирования сказать почти нечего. Просто передайте в него vector, который требуется скопировать, и все.
vector vec2(vec);
В этом случае vec2будет содержать такое же число элементов, что и vec, и каждый из этих элементов будет копией элемента vecс таким же индексом. Каждый элемент копируется с помощью конструктора копирования string. Так как здесь используется конструктор, буфер vec2имеет размер, достаточный для хранения всего, что есть в vec.
assignработает аналогично, за исключением того, что за кулисами выполняется дополнительная работа, связанная с тем, что теперь дело касается целевого vector который уже может содержать данные. Во-первых, требуется удалить элементы, которые оказались, так сказать, под ногами. Вначале assignдля каждого из объектов, уже содержащихся в vec2, вызывает деструктор. После этого он проверяет размер буфера vec2, чтобы убедиться, что он достаточно большой, чтобы вместить то, что находится в vec. Если он не достаточен, assignизменяет размер буфера под размещение новых данных. Наконец, он копирует каждый элемент.
Кроме того, assignможно использовать для копирования подмножества последовательности. Например, если требуется скопировать подмножество элементов vec, просто укажите при вызове assignнеобходимый диапазон.
vector::iterator p;
p = std::find(vec.begin(), vec.end(), "new");
vec2.assign(vec.begin(), p);
vecPrint(vec2);
В этом случае assignскопирует все до, но не включая, p. Причиной этого является соглашение, по которому во всех контейнерах и алгоритмах стандартной библиотеки assign(first, last)копирует элементы, на которые указывает first, до, но не включая, элемент, на который указывает last. Такой диапазон, который включает первый элемент, но не включает последний, часто обозначается как (first, last) .
Читать дальше