Vivek Basappa
Vivek Basappa

Reputation: 383

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

Upvotes: 21

Views: 5552

Answers (4)

justin
justin

Reputation: 104698

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.

Upvotes: 4

Michael Burr
Michael Burr

Reputation: 340316

You're binding the const& to a temporary, which doesn't live beyond the call to the constructor. The C++03 standard specfically says "a temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits" (12.2/5 "Temporary objects").

So your code has undefined behavior - you might get nonsense, or something that appears to be 'working'.

FWIW, MSVC 2010 gives the following warning on that code:

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

Upvotes: 3

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234584

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.

Upvotes: 19

Borealid
Borealid

Reputation: 98509

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.

Upvotes: 24

Related Questions