Ініціалізація за замовчуванням std :: array?


103

std::arrayЧи маю я в C ++ 11 гарантію, що синтаксис std::array<T, N> x;ініціалізує за замовчуванням всі елементи масиву?

РЕДАГУВАТИ : якщо ні, чи існує синтаксис, який працюватиме на всіх масивах (включаючи масиви нульового розміру), щоб ініціалізувати всі елементи за значенням за замовчуванням?

EDIT : на cppreference в описі конструктора за замовчуванням сказано:

(constructor) (implicitly declared) (public member function)
default-constructs or copy-constructs every element of the array 

тож відповідь може бути ствердною. Але я хотів би бути впевненим у цьому відповідно до стандарту чи майбутнього стандарту.


Не думайте. Це оголошено за замовчуванням, тому в основному це еквівалент T x[N]синтаксису.
Rapptz

Відповіді:


148

За визначенням, ініціалізація за замовчуванням - це ініціалізація, яка відбувається, коли не вказана інша ініціалізація; мова C ++ гарантує вам, що будь-який об'єкт, для якого ви не надаєте явного ініціалізатора, буде ініціалізованим за замовчуванням (C ++ 11 §8.5 / 11). Сюди входять об'єкти типу std::array<T, N>і T[N].

Майте на увазі, що існують типи, для яких ініціалізація за замовчуванням не має ефекту і залишає значення об’єкта невизначеним: будь-який некласовий тип, що не є масивом (§8.5 / 6). Отже, ініціалізований за замовчуванням масив об'єктів з такими типами матиме невизначене значення, наприклад:

int plain_int;
int c_style_array[13];
std::array<int, 13> cxx_style_array;

І масив c-стилю, і std::arrayзаповнені цілими числами невизначеного значення, як plain_intі невизначене значення.

Чи існує синтаксис, який буде працювати на всіх масивах (включаючи масиви нульового розміру), щоб ініціалізувати всі елементи за значенням за замовчуванням?

Я здогадуюсь, що коли ви говорите "до значення за замовчуванням", ви дійсно маєте на увазі "ініціалізувати всі елементи до T{}". Це не ініціалізація за замовчуванням , це ініціалізація значення (8.5 / 7). Ви можете запросити ініціалізацію значення досить легко в C ++ 11, давши кожному оголошенню порожній ініціалізатор:

int plain_int{};
int c_style_array[13]{};
std::array<int, 13> cxx_style_array{};

Що призведе до ініціалізації значення елементів масиву по черзі, в результаті чого plain_old_intі всі члени обох типів масивів будуть ініціалізовані до нуля.


А що, якщо це член класу: struct X {std :: array <int, 12> дюжина; X (): десяток () {} Чи це мені дає дванадцять нулів?
gerardw

4
@gerardw Відповідно до стандарту, так воно і є. Остерігайтеся помилок у MSVC, він не може правильно реалізувати деякі випадки ініціалізації значень.
Кейсі

1
дійсно Boost говорить так і обходить це за допомогою свого boost::value_initialized посилання, але я вважаю, що VC12 (VS2013) має набагато кращу підтримку зараз.
v.oddou

1
Змушує мене побажати комітету змінити стандарт на значення за замовчуванням, ініціалізація значення та підірване значення на запит. Тобто std :: array <int, 12> = {std :: undetermined}; або щось інше
Viktor Sehr

На практиці, що взагалі означає ініціалізувати щось до невизначеного значення? Яка альтернатива?
Ендрю

21

Ініціалізація за замовчуванням - це термін із стандарту, який потенційно означає відсутність ініціалізації взагалі, тому ви, мабуть, маєте на увазі нульову ініціалізацію .

Опис на cppreference.com насправді трохи вводить в оману. std::arrayє агрегованим класом, і якщо тип елемента примітивний, це POD: "звичайні старі дані", із семантикою, що точно відповідає мові C. Імпліцитно визначений конструктор std::array< int, N >є тривіальним, який абсолютно нічого не робить.

Синтаксис, подібний std::array< int, 3 >()або std::array< int, 3 > x{}який надає нульові значення, не робить цього за допомогою конструктора. Отримання нулів є частиною ініціалізації значення , зазначеної в C ++ 11 §8.5 / 8:

Ініціалізувати значення об'єкта типу T означає:

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

std::arrayне має наданого користувачем конструктора за замовчуванням, тому він отримує нульову ініціалізацію. Він має неявно визначений конструктор за замовчуванням, але він є тривіальним, тому він ніколи не ініціалізується за замовчуванням. (Але це не має значення, оскільки тривіальна ініціалізація за визначенням не впливає на час виконання.)

якщо ні, чи існує синтаксис, який буде працювати на всіх масивах (включаючи масиви нульового розміру) для ініціалізації всіх елементів за значенням за замовчуванням?

Масиви у стилі С std::arrayє обома агрегатами, а спосіб повністю нульової ініціалізації будь-якого агрегату - це синтаксис = {}. Це працює з C ++ 98. Зверніть увагу, що масиви у стилі С не можуть мати нульовий екстент, і sizeof (std::array< X, 0 >)це не нуль.


6

І, T x[N];і std::array<T, N> x;за замовчуванням ініціалізують кожен елемент масиву.

Наприклад, якщо T = std::string, кожен елемент буде порожнім рядком. Якщо Tце клас без конструктора за замовчуванням, обидва не зможуть скомпілювати. Якщо T = int, кожен елемент матиме невизначене значення (за винятком випадків, коли це оголошення знаходиться в області простору імен)


0

Перш за все, T x [N] ініціалізує елементи за замовчуванням, хоча ініціалізація за замовчуванням скалярного типу T насправді нічого не робить. Вищезазначене також стосується std :: array x. Я думаю, що вам потрібна ініціалізація списку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.