std::vector
должен инициализировать значения в массиве так или иначе, что означает, что нужно вызвать конструктор (или конструктор-копию). Поведение vector
(или любого класса контейнера) не определено, если вы должны получить доступ к неинициализированному разделу массива, как если бы он был инициализирован.
Лучший способ - использовать reserve()
и push_back()
, чтобы использовать конструктор-копию, избегая построения по умолчанию.
Использование Пример кода:
struct YourData {
int d1;
int d2;
YourData(int v1, int v2) : d1(v1), d2(v2) {}
};
std::vector<YourData> memberVector;
void GetsCalledALot(int* data1, int* data2, int count) {
int mvSize = memberVector.size();
// Does not initialize the extra elements
memberVector.reserve(mvSize + count);
// Note: consider using std::generate_n or std::copy instead of this loop.
for (int i = 0; i < count; ++i) {
// Copy construct using a temporary.
memberVector.push_back(YourData(data1[i], data2[i]));
}
}
Единственная проблема с вызовом reserve()
(или resize()
), как это то, что вы можете в конечном итоге вызова копировать-конструктор чаще, чем вам нужно. Если вы можете сделать хорошее предсказание относительно конечного размера массива, то лучше, чтобы reserve()
пробел один раз в начале. Если вы не знаете окончательный размер, хотя, по крайней мере, количество копий будет минимальным в среднем.
В текущей версии C++ внутренний цикл немного неэффективен, поскольку временное значение создается в стеке, копируется в память векторов и, наконец, временно уничтожается. Однако следующая версия C++ имеет функцию R-Value reference (T&&
), которая поможет.
Интерфейс, предоставленный std::vector
, не позволяет использовать другой вариант, который должен использовать некоторый заводский класс для создания значений, отличных от значения по умолчанию. Вот грубый пример того, что эта модель будет выглядеть реализованы в C++:
template <typename T>
class my_vector_replacement {
// ...
template <typename F>
my_vector::push_back_using_factory(F factory) {
// ... check size of array, and resize if needed.
// Copy construct using placement new,
new(arrayData+end) T(factory())
end += sizeof(T);
}
char* arrayData;
size_t end; // Of initialized data in arrayData
};
// One of many possible implementations
struct MyFactory {
MyFactory(int* p1, int* p2) : d1(p1), d2(p2) {}
YourData operator()() const {
return YourData(*d1,*d2);
}
int* d1;
int* d2;
};
void GetsCalledALot(int* data1, int* data2, int count) {
// ... Still will need the same call to a reserve() type function.
// Note: consider using std::generate_n or std::copy instead of this loop.
for (int i = 0; i < count; ++i) {
// Copy construct using a factory
memberVector.push_back_using_factory(MyFactory(data1+i, data2+i));
}
}
Делать это означает, что вы должны создать свой собственный вектор класс. В этом случае это также усложняет то, что должно было быть простым примером. Но могут быть времена, когда использование такой заводской функции, как это, лучше, например, если вставка зависит от какого-либо другого значения, и вам пришлось бы в противном случае безоговорочно построить дорогостоящее временное, даже если оно действительно не понадобилось.
Примечание - использование резерва() не является решением проблемы, так как вы не можете легально получить доступ к данным, что это в местах конца() и выше. – 2008-09-18 20:36:23
Другое уточнение: это не значит, что конструктор инициализирует значения равными 0. Это то, что делает resize вызывает insert, что делает. – 2008-09-18 20:42:06
Не могли бы вы также дать нам объявление структуры? Спасибо ... :-) – paercebal 2008-09-18 21:00:26