Подтвердить что ты не робот

Конструктор С++: мусор при инициализации ссылки const

что не так с этим кодом, почему я получаю неправильный ответ:

class X
{
private:
        const int a;
        const int& b;
public:
        X(): a(10) , b(20)
        {
        //      std::cout << "constructor : a " << a << std::endl;
        //      std::cout << "constructor : b " << b << std::endl;
        }

        void display()
        {
            std::cout << "display():a:" << a << std::endl;
            std::cout << "display():b:" << b << std::endl;

        }
};


int
main(void)
{
        X x;
        x.display();
return 0;
}

Приведенный выше код даст мне результат как

display():a:10
display():b:1104441332

Но если я удаляю прокомментированные 2 строки внутри конструктора по умолчанию, он дает правильный результат, который

constructor : a 10
constructor : b 20
display():a:10
display():b:20

Пожалуйста, помогите, спасибо

4b9b3361

Ответ 1

Вы инициализируете b как ссылку на временную.

Значение 20 создается и существует только для области действия конструктора.

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

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

См. Содержит ли ссылка на константу срок службы временного?; ответ fooobar.com/questions/50373/... ссылается на соответствующий раздел стандарта С++, в частности, следующий текст:

A temporary bound to a reference member in a constructor’s ctor-initializer
(12.6.2) persists until the constructor exits.

Вот почему вы всегда получаете правильное значение в печати внутри конструктора и редко (но, возможно, иногда!) после. Когда конструктор выходит, ссылка оборвалась и все ставки отключены.

Ответ 2

Я позволю своему компилятору ответить на этот вопрос:

$ g++ -std=c++98 -Wall -Wextra -pedantic test.cpp
test.cpp: In constructor 'X::X()':
test.cpp:9:26: warning: a temporary bound to 'X::b' only persists until the constructor exits [-Wextra]
$

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

Ответ 3

b относится к временному. То, что вы прочитали (при печати), является недопустимым местоположением к моменту его считывания, поскольку временный 20 технически вышел из области видимости.

Чтобы объяснить непоследовательные результаты:

Это поведение undefined. То, что вы видите, может быть другим, если вы:

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

Вы всегда должны избегать поведения undefined.

Но почему изменилось значение? Ваша ссылка скорее всего относится к адресу стека, который был переписан (например, повторно использован) к моменту его печати. ​​

Ответ 4

Вы привязываете const& к временному, который не живет за вызовом конструктора. В стандарте С++ 03 уточняется, что "временная привязка к ссылочному элементу в конструкторах ctor-initializer (12.6.2) сохраняется до тех пор, пока конструктор не выйдет" (12.2/5 "Временные объекты" ).

Таким образом, ваш код имеет поведение undefined - вы можете получить бессмыслицу или что-то, что кажется "рабочим".

FWIW, MSVC 2010 дает следующее предупреждение в этом коде:

C:\temp\test.cpp(12) : warning C4413: 'X::b' : reference member is initialized to a temporary that doesn't persist after the constructor exits