Используйте assignили конструктор копирования вместо самостоятельного циклического перебора. Это значит, не копируйте каждый элемент, перебирая vecи помещая элементы в конец vec2в цикле. Это потребует от вас большой избыточности кода и отключит все оптимизации, которые могут присутствовать в реализации assignи конструктора копирования стандартной библиотеки.
6.4. Хранение указателей в векторе
Проблема
С целью повышения эффективности или по другим причинам невозможно хранить копии объектов в vector, но их требуется как-то разместить.
Решение
Сохраните в vectorуказатели на объекты, а не копии самих объектов. Но при этом не забудьте удалить объекты с помощью delete, так как vectorэтого за вас не сделает. Пример 6.4 показывает, как объявить vectorуказателей и работать с ним.
Пример 6.4. Использование векторов указателей
#include
#include
using namespace std;
static const int NUM_OBJECTS = 10;
class MyClass { /*...*/ };
int main() {
vector vec;
MyClass* p = NULL;
// Загрузить в vector объекты MyClass
for (int i = 0; i < NUM_OBJECTS; i++) {
p = new MyClass();
vec.push_back(p);
}
// Выполнить обработку данных, затем удалить объекты, когда
// они уже не нужны
for (vector::iterator pObj = vec.begin();
pObj != vec.end(); ++pObj) {
delete *pObj; // заметьте, что здесь удаляется то на что указывает pObj,
// который является указателем
}
vec.clear(); // Очистить содержимое, чтобы больше никто не попытался
// удалить его еще раз
}
Обсуждение
Сохранить указатели в vectorможно точно так же, как и все остальное. Объявите vector указателей таким образом:
vector vec;
Здесь важно запомнить, что vectorхранит значения , не обращая внимания на то, что они означают. Следовательно, он не знает, что для указателей перед их удалением следует использовать delete. Если выделить память, затем поместить указатели в память vector, то по окончании работы следует самостоятельно удалить память. Не дайте ввести себя в заблуждение термину «контейнер», думая, что если в vectorсохранить указатель, то это подразумевает владение им.
После удаления указателей следует явно очистить vector— по той же причине, по которой следует присваивать переменным-указателям по окончании работы с ними значение NULL. Это предотвратит ошибочное повторное удаление.
6.5. Хранение объектов в списке
Проблема
Требуется хранить элементы в виде последовательности, но vector не соответствует всем требованиям. В частности, требуется иметь возможность эффективно добавлять и удалять элементы в середине последовательности, а не только в ее конце.
Решение
Для хранения данных используйте list, объявленный в . listпредлагает более высокую производительность и большую гибкость при изменении последовательности в произвольных местах. Пример 6.5 показывает, как использовать list, а также демонстрирует некоторые из его уникальных операций.
Пример 6.5. Использование list
#include
#include
#include
#include
using namespace std;
// Простая функция для печати
template
struct printer {
void operator()(const T& s) {
cout << s << '\n';
}
};
bool inline even(int n) {
return(n % 2 == 0);
}
printer strPrinter;
printer intPrinter;
int main() {
list lstOne;
list lstTwo;
lstOne.push_back("Red");
lstOne.push_back("Green");
lstOne.push_back("Blue");
lstTwo.push_front("Orange");
lstTwo.push_front("Yellow");
lstTwo.push_front("Fuschia");
for_each(lstOne.begin(), // Напечатать каждый элемент списка,
lstOne.end(), // используя пользовательскую функцию печати
strPrinter);
lstOne.sort(); // list содержит методы для сортировки
lstTwo.sort();
lstOne.merge(lstTwo); // Объединить два списка и напечатать
for_each(lstOne.begin(), // результаты (перед объединением списки должны
lstOne.end(), // быть отсортированы)
strPrinter);
list intLst;
intLst.push_back(0);
intLst.push_back(1);
intLst.push_back(2);
intLst.push_back(3);
intLst.push_back(4);
// Удалить все значения больше 2
intLst.remove_if(bind2nd(greater(), 2));
for_each(intLst.begin(), intLst.end(), intPrinter);
// Или удалить все четные значения
intLst.remove_if(even);
Читать дальше