Инициализированные значения объектов в конструкторах С++ 11 и std::vector
В С++ существует несколько веских причин использовать массив C над std::vector
. Одной из немногих убедительных причин, по крайней мере, с С++ 03, был тот факт, что невозможно использовать вектор для выделения неинициализированного массива объектов. Конструктор "fill" для std::vector
:
vector(size_type count, const T& value = T())
Значит, что...
int* array = new array[1000000];
вероятно, будет намного более эффективным, чем:
std::vector<int> v(1000000);
... так как вектор-конструктор должен будет нуль инициализировать массив целых чисел. Таким образом, при работе с вектором POD нет реального эквивалента malloc
; лучшее, что вы можете получить, эквивалентно calloc
.
С++ 11, похоже, изменил это, с понятием "инициализация ценности". В С++ 11 std::vector
имеет новый конструктор, который принимает единственное значение size_type
без аргумента по умолчанию. Это "значение-инициализирует" все элементы вектора. Стандарт С++ 11 различает "инициализацию значения" и "нулевую инициализацию".
Я понимаю, что "инициализация значений" эквивалентна вызову конструктора по умолчанию на T
. Если T
- тип POD, такой как int
, то конструктор по умолчанию просто создает неинициализированное целое число. Таким образом, в С++ 11 explicit vector::vector(size_type count)
действительно эквивалентен malloc
, если T
является POD.
Однако мое понимание этого основано на проекте стандарта С++ 11, а не на окончательном стандарте.
Вопрос. Является ли мое понимание правильным здесь? Предоставляет ли explicit vector::vector(size_type count)
неинициализированный массив (похожий на malloc
), если T
является POD?
Ответы
Ответ 1
Вопрос. Является ли мое понимание правильным здесь? Предоставляет ли explicit vector::vector(size_type count)
неинициализированный массив (аналогично malloc
), если T
является POD?
Нет. Здесь есть разница между С++ 03 и С++ 11, но это не так. Разница в том, что в С++ 03, vector<T>(N)
будет по умолчанию строить a T
, а затем сделать N
его копии для заполнения вектора.
В то время как в С++ 11, vector<T>(N)
будет заполнять вектор по умолчанию, построив T
N
раз. Для типов POD эффект идентичен. Действительно, я ожидал бы, что для почти всех типов эффект будет идентичным. Однако для чего-то вроде unique_ptr
(тип только для перемещения) разница имеет решающее значение. Семантика С++ 03 никогда не будет работать, так как вы не можете сделать копию типа только для перемещения.
Итак:
vector<unique_ptr<int>> v(10);
создает вектор из 10 null unique_ptrs (которые не являются копиями друг друга).
В редком случае, когда это имеет значение, и вам нужно поведение С++ 03, которое можно легко выполнить с помощью:
vector<T> v(10, T());
Ответ 2
Примечание: инициализация значения происходит в распределителе, поэтому, если вы хотите, чтобы вектор выполнял инициализацию по умолчанию вместо инициализации значения для построенных по умолчанию элементов, вы можете сделать что-то вроде:
template<typename T>
struct DefaultInitAllocator {
template<typename U>
void construct(U* p)
{ ::new (static_cast<void*>(p)) U; }
template<typename U, typename... Args>
void construct(U* p, Args&&... args)
{ ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...); }
// ... rest of the allocator interface
};
// ...
typedef std::vector<int, DefaultInitAllocator<int>> DefaultInitVectorInt;