Почему & quot; ctor () = default & quot; изменить поведение, когда присутствуют другие конструкторы?

Почему

struct wrapper
{
explicit wrapper(void *);
wrapper() = default;
int v;
};

int main() { return wrapper().v; }  // You should run this in Debug mode

вернуть 0xCCCCCCCC, в то время как

struct wrapper { wrapper() = default; int v; };
int main() { return wrapper().v; }

а также

struct wrapper { int v; };
int main() { return wrapper().v; }

оба возвращаются 0?

11

Решение

В течение Значение инициализация, если T является типом класса без предоставленного пользователем или удаленного конструктора по умолчанию, тогда объект нулевой инициализируется (§8.5 / 8,2). Это действительно так с wrapper,

Ваш первый пример соответствует третьему случаю для инициализации нуля (§8.5 / 6.1, выделение мое)

— если T является скалярным типом (3.9), объект инициализируется значением, полученным путем преобразования целочисленного литерала
0 (ноль) до T;

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

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

— если T является типом массива, каждый элемент инициализируется нулями

— если T является ссылочным типом, инициализация не выполняется

Итак, в вашем первом примере, v должен быть инициализирован нулем. Это похоже на ошибку.

Во втором и третьем примере у вас больше нет предоставленного пользователем конструктора, но у вас есть конструктор по умолчанию, который не предоставлен или не удален пользователем, поэтому ваш пример все еще попадает в третий случай для инициализации нуля, который заключается в инициализировать нулями каждый нестатический элемент данных. ВС там правильно.

4

Другие решения

Это похоже на ошибку в MSVC. Во всех трех случаях wrapper не имеет предоставленного пользователем конструктора по умолчанию, поэтому инициализация с wrapper() вызывает:

(Все цитаты из n3690)

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

(благодаря dyp), это приведет к нулевой инициализации int v

Затем инициализация отсылает нас к правилу:

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

Состояние правил нулевой инициализации:

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

int v будучи членом данных wrapper инициализируется нулем в соответствии с:

(8.5 / 6) если T является скалярным типом (3.9), объект инициализируется значением, полученным путем преобразования целочисленного литерала 0 (нуля) в T

Который не поведение, которое вы наблюдаете.

4

По вопросам рекламы [email protected]