Гарантировано ли, что конструктор по умолчанию инициализирует встроенные типы автоматически до 0?

Прежде чем вы начнете отмечать это как дубликат, я уже прочитал this . Но это не отвечает на мой вопрос. Связанный вопрос говорит о С++ 98 и С++ 03, но мой вопрос о конструкторе по умолчанию, представленном С++ 11.

Рассмотрим следующую программу (см. живое демо здесь):

#include <iostream>
struct Test
{
    int s;
    float m;
    Test(int a,float b) : s(a),m(b)
    { }
    Test()=default;
}t;
int main()
{
    std::cout<<t.s<<'\n';
    std::cout<<t.m<<'\n';
}

Мой вопрос в том, что конструктор, предоставленный компилятором по умолчанию, всегда инициализирует встроенные типы по умолчанию 0 в С++ 11 и С++ 14, когда они являются членами class и struct. Является ли это поведение гарантированным стандартом С++ 11?

Ответ 1

Test = default будет по умолчанию инициализировать свои члены. но для типа int или float инициализация по умолчанию отличается от инициализации значения

так

Test t; // t.s and t.m have unitialized value

тогда

Test t{}; // t.s == 0 and t.m == 0.0f;

Ответ 2

В этот вопрос встроены два отдельных вопроса.

  • Что означает = default для конструктора по умолчанию? Из [class.ctor]:

    Конструктор по умолчанию, который по умолчанию и не определен как удаленный, неявно определяется, когда он используется как odr (3.2), чтобы создать объект своего типа класса (1.8) или когда он явно дефолт после его первого объявления. Неявно определенный конструктор по умолчанию выполняет набор инициализаций класса, который был бы выполненный пользовательским конструктором по умолчанию для этого класса без инициализатора ctor (12.6.2) и пустого соединение-оператор.

    То есть, Test() = default в точности эквивалентен Test() { }, который по умолчанию инициализирует s и m, который устанавливает их в какое-то неопределенное значение.

  • Как инициализируются t.s и t.m? Да, это отдельный вопрос из (1), потому что мы не просто вызываем конструктор по умолчанию здесь. Из [basic.stc.static]:

    Все переменные, которые не имеют динамической продолжительности хранения, не имеют продолжительности хранения потоков и не локальные имеют статическую продолжительность хранения.

    и из [basic.start.init]:

    Переменные со статической продолжительностью хранения (3.7.1) или продолжительностью хранения потоков (3.7.2) должны быть инициализированы нулями (8.5)перед любой другой инициализацией.

    Таким образом, t.s и t.m гарантированно равны 0, хотя, если мы построили по умолчанию локальный Test, они не будут.

Ответ 3

Как уже было сказано, не гарантируется, что конструктор по умолчанию "автоматически инициализирует встроенные типы автоматически до 0".

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

#include <iostream>

struct Test
{
    int s;
    float m;
    Test(int a,float b) : s(a),m(b)
    { }
    Test()=default;
};

int main()
{
    char* buf = new char[sizeof(Test)];
    Test* t = new (buf) Test;

    std::cout << t->s << '\n';
    std::cout << t->m <<'\n';

    t->s = 42;
    t->m = 4.2;

    t->~Test();
    t = new (buf) Test;

    std::cout << t->s << '\n';
    std::cout << t->m <<'\n';
}

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

Однако, скорее всего, вы увидите что-то вроде этого:

0
0
42
4.2

Здесь этот код на cpp.sh - http://cpp.sh/9fdj

Ответ 4

Нет, конструктор по умолчанию ничего не делает! Чтобы инициализировать переменные-члены, вы можете написать:

struct Test
{
    int s = 0;
    float m = 3.3;
    Test(int a,float b) : s(a),m(b)
    { }
    Test()=default;
};

Посмотрите на это: С++ ctor = default

Ответ 5

Для всех целей:

Test() = default;

эквивалентно:

Test() {}

Поэтому он не инициализирует элементы встроенных типов.