std :: vector of struct: каковы будут начальные значения членов структуры после изменения размера вектора? - PullRequest
3 голосов
/ 27 марта 2019
#include <vector>
#include <iostream>

typedef struct {
   unsigned short a;
   unsigned short b;
   unsigned long  c;
}T;

int main(int,char**)
{
    std::vector<T> v;
    v.resize(256);
    std::cout << "a=" << v[0].a << " b=" << v[0].b << " c=" << v[0].c << "\n";
    return 0;
}

Что будет v[0].ab и c)?

Я начинаю смотреть на проект N4659 Рабочий проект, стандарт для программирования Язык C ++ ищет vector::resize:

26.3.11.3 емкость вектора [vector.capacity] (в разделе 13)

void resize(size_type sz);

Эффекты : Если sz < size(), стирает последний size() - sz элементов из последовательности. В противном случае добавляет sz - size() вставленные по умолчанию элементы в последовательность.

оттуда мне нужно знать, что означает по умолчанию , и я прихожу к:

26.2.1 Общие требования к контейнерам [container.requirements.general] (в пункте 15.2)

- Элемент X равен по умолчанию вставлен , если он инициализирован оценка выражения

allocator_traits<A>::construct(m, p)

где p - адрес неинициализированного хранилища для элемента выделено в пределах X.

Теперь мне нужно знать, что происходит внутри construct, я нашел эту заметку

26.2.1 Общие требования к контейнерам [container.requirements.general] (в конце пункта 15)

[ Примечание : контейнер вызывает allocator_traits<A>::construct(m, p, args) построить элемент на p, используя args, с m == get_allocator(). Конструкция по умолчанию в allocator вызовет ::new((void*)p) T(args), но специализированные распределители могут выбрать другое определение. - конец примечание ]

Я в порядке? Использует ли мой фрагмент специализированные распределители ? Я думаю, что в конце мой фрагмент вызовет new T(), и теперь, согласно https://stackoverflow.com/a/8280207 Я думаю, a, b и c будут 0, я прав?

Ответы [ 4 ]

6 голосов
/ 27 марта 2019

Да, вы правы.Вы не использовали специализированный (настраиваемый) распределитель.Наконец элементы получают значение, инициализированное .From DefaultInsertable :

По умолчанию это вызовет place-new, как ::new((void*)p) T() (то есть инициализирует значение объекта, на который указывает p).

И в результате инициализации значения все члены T будут инициализироваться нулями.

(выделено мной)

если T является типом класса с конструктором по умолчанию, который не предоставлен и не удален пользователем (то есть это может быть класс с неявно определенным или дефолтным конструктором по умолчанию), объект равен нулю-initialized и затем инициализируется по умолчанию, если у него есть нетривиальный конструктор по умолчанию;

4 голосов
/ 27 марта 2019

Поведение по умолчанию

allocator_traits<A>::construct(m, p)

определено в [allocator.traits.members] / 5 если в нем указано, что

Эффекты:Звонит a.construct(p, std::forward<Args>(args)...), если этот звонок правильно сформирован;в противном случае вызывается ::new (static_­cast<void*>(p)) T(std::forward<Args>(args)...).

Поскольку std::vector<T> v; использует распределитель по умолчанию std::allocator, а std::allocator не имеет члена construct, вы возвращаетесь к новой инициализации размещения, и если выразверните его, у вас будет

::new (static_­cast<void*>(p)) T();

, и если мы посмотрим, что T() мы получим от [dcl.init] / 11 , что

Объект, инициализатором которого является пустой набор скобок, т. Е. (), Должен быть инициализирован значением.

и [dcl.init] / 8 указывает это значениеинициализация будет

, если T является (возможно, cv-квалифицированным) типом класса без предоставленного пользователем или удаленного конструктора по умолчанию, то объект инициализируется нулями и проверяются семантические ограничения для инициализации по умолчаниюи если T имеет нетривиальный конструктор по умолчанию, объект инициализируется по умолчанию;

Таким образом, все члены каждого вновь созданного объекта будут инициализироваться нулем, что означает, что в этом случае все они будутимеют значение 0, так как они построеныв типах.

3 голосов
/ 27 марта 2019

Я в порядке? Использует ли мой фрагмент специализированные распределители?

Да, нет, распределитель не специализирован. Распределитель по умолчанию, используемый std::vector<T> - std::allocator<T>. В настоящее время std::allocator<T> имеет значение , в котором по-прежнему указывается construct член , который делает то же самое. Но это устаревший член. Несмотря на это, даже если он будет полностью удален в будущем, вызов через std::allocator_traits будет вести себя так же.

[allocator.traits.members]

template <class T, class... Args>
  static void construct(Alloc& a, T* p, Args&&... args);

Эффекты : Звонит a.construct(p, std​::​forward<Args>(args)...), если этот вызов правильно сформирован; в противном случае вызывает ​::​new(static_­cast<void*>(p)) T(std​::​forward<Args>(args)...).

Что касается new T(), то вы на 100% правы.

0 голосов
/ 27 марта 2019

Я в порядке?

Да.

Использует ли мой фрагмент специальные распределители?

Нет.Вы используете распределитель по умолчанию, который std::allocator.

Я думаю, что в конце мой фрагмент вызовет new T (), и теперь, согласно https://stackoverflow.com/a/8280207 Я думаю, a, b и c, будут 0, я прав?

Правильно.

...