Почему член 'float x' инициализируется с `0.'для объектов' a` и ' b` в main()? [дубликат]


На этот вопрос уже есть ответ здесь:

Может ли кто-нибудь указать, какое предложение в стандарте поддерживает следующее поведение, полученное в Coliru, для фрагмента:

#include <iostream>

class A
{
    int i;
    float x;

    public:
    A() : i(10) {}
    A(int i) : i(i) {}
    int GetI() { return i; }
    float GetF() { return x; }
};


int main()
{
    A a;
    A b(1);
    A x{};
    A y{1};
    std::cout << a.GetI() << 'n';
    std::cout << a.GetF() << 'n';
    std::cout << b.GetI() << 'n';
    std::cout << b.GetF() << 'n';
    std::cout << x.GetI() << 'n';
    std::cout << x.GetF() << 'n';
    std::cout << y.GetI() << 'n';
    std::cout << y.GetF() << 'n';
}

Код печатает:

10
0 1
0 10
0
1
0

Редактировать:

Этот абзац взят из 4-го издания TCPL, страница 490:

Для этого правила не так чисты, как нам хотелось бы. Для статически выделенные объекты (§6.4.2), правила точно такие же, как если бы вы использовали {}, таким образом, значение альфа равно {"","",0}. Однако для локальных переменных и объекты свободного хранения, инициализация по умолчанию выполняется только для члены класса type и члены встроенного типа остаются неинициализирован, поэтому значение бета равно {"","", неизвестно}.
Мистер Страуструп ничего не говорит о неопределенном поведении.
4 8

4 ответа:

0 является одним из возможных произвольных значений, которые может получить неинициализированная переменная: программа имеет неопределенное поведение. Учитывая, что существует Справедливая вероятность того, что память начинается с нуля, инициализированного, 0 является вероятным результатом: представление IEEE 754 для 0 оказывается все нули. Однако нет никакой гарантии, что значение будет 0.

At Mat указал, что чтение неинициализированной переменной в C++ в неопределенном поведении, что означает, что все может (и, вероятно, будет, в некоторой системе) произойти.

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

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

Что именно вы ожидаете от слова "неизвестный"? 0 - вполне разумное значение для неинициализированной переменной с неопределенным значением. Это просто чистая случайность.

Важно то, что float былНе инициализирован , и в цитируемом отрывке BS не говорит о неопределенном поведении, потому что он ссылается не на синтаксис, о котором вы спрашиваете, а на агрегатную инициализацию (и ее варианты).

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

Но это выходит еще дальше. Поскольку стандарт C++ определяет преобразование lvalue - >rvalue для неинициализированных данных как неопределенное поведение, компилятору совершенно разрешено делать все, что он хочет для вашего кода, даже код, который не связан с этой переменной, и даже до первого доступа к этой переменной (до тех пор, пока он может доказать, что неопределенное чтение переменной приходит, что доказательство обычно легко только в пределах одного и того же базового блока).