C++ constructor: garbage while initialization of const reference

前端 未结 4 769
陌清茗
陌清茗 2020-12-15 18:45

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)         


        
相关标签:
4条回答
  • 2020-12-15 19:14

    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.

    0 讨论(0)
  • 2020-12-15 19:19

    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.

    0 讨论(0)
  • 2020-12-15 19:22

    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.

    0 讨论(0)
  • 2020-12-15 19:22

    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
    
    0 讨论(0)
提交回复
热议问题