Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ constructor: garbage while initialization of const reference

what is wrong with this code, why do I get wrong answer:

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;
}

The above code will give me the result as

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

But If I remove the commented 2 lines inside the default constructor it gives me proper result which is

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

please help, Thank you

like image 243
Vivek Basappa Avatar asked Feb 04 '12 06:02

Vivek Basappa


3 Answers

You are initializing b as a reference to a temporary.

The value 20 is created and exists only for the scope of the constructor.

The behavior of the code after this is very interesting - on my machine, I get different values from the ones you posted, but the fundamental behavior is still nondeterministic.

This is because when the value to which the reference points falls out of scope, it begins to reference garbage memory instead, giving unpredictable behavior.

See Does a const reference prolong the life of a temporary?; the answer https://stackoverflow.com/a/2784304/383402 links to the relevant section of the C++ standard, specifically the below text:

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

This is why you always get the right value in the print within the constructor, and rarely (but possibly sometimes!) after. When the constructor exits, the reference dangles and all bets are off.

like image 113
Borealid Avatar answered Nov 07 '22 12:11

Borealid


I'll let my compiler answer this one:

$ 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]
$

You should turn on the warnings on your compiler as well.

like image 19
R. Martinho Fernandes Avatar answered Nov 07 '22 11:11

R. Martinho Fernandes


b refers to a temporary. What you have read (when printing) is an invalid location by the time it is read since the temporary 20 has technically gone out of scope.

To explain inconsistent results:

It is undefined behavior. What you see may be different if you:

  • change your compiler
  • change your compiler settings
  • build for another architecture
  • change your class' member layout
  • add or remove things from the memory region near the instance of x
  • etc.

You should always always avoid undefined behavior.

But why would the value change? Your reference likely refers to a stack address which has been rewritten (e.g. reused) by the time it's printed.

like image 4
justin Avatar answered Nov 07 '22 10:11

justin