为什么从临时初始化的引用成员仍然可读?

时间:2012-09-26 13:32:32

标签: c++ reference initialization

  

可能重复:
  Can a local variable's memory be accessed outside its scope?
  C++ constructor: garbage while initialization of const reference

这个问题与我前一段时间提出的另一个问题直接相关:"Opaque reference instead of PImpl. Is it possible?"

假设我们有一个类,其中包含其他类的引用成员,该类在构造函数中初始化为临时变量:

#include <iostream>

struct B
{
    B(int new_x = 10) : x(new_x) { std::cout << "B constructed\n"; }
    ~B() { std::cout << "B destroyed\n"; }

public:
    int x;
};

struct A
{
    A()
    : b( B(23) )
    {
        std::cout << "A constructed\n";
    }

    void Foo()
    {
        std::cout << "A::Foo()\n";
    }

    ~A()
    {
        std::cout << "A destroyed\n";
    }

public:
    const B& b;
};

int main()
{
    A a;
    a.Foo();
    cout << "x = " << a.b.x << endl;
}

当我运行上面的代码时,输​​出是:

B constructed
B destroyed
A constructed
A::Foo()
x = 23
A destroyed

似乎即使临时被破坏因此引用成员应该无效,引用成员的整数字段仍然是可读的。为什么它仍然有效?

3 个答案:

答案 0 :(得分:1)

未定义的行为。在您的情况下会发生这样的情况,即临时B之前占用的内存在引用之前不会被覆盖。下次运行程序时,可能会发生任何事情。

注意表面上相似的

const B &b = B();

确实有定义的行为;临时B的生命周期通过引用绑定扩展。这仅适用于参考变量,而不适用于参考成员。

答案 1 :(得分:1)

如果引用无效,那并不意味着它不可读。这意味着它不引用有效对象。它可能会也可能不会指某些可访问的内存;如果确实如此,你可能会或者可能不会发现内存中包含过去任何对象的残余。

总而言之,行为未定义。

答案 2 :(得分:1)

分配给临时B的内存现在无效,但尚未用于任何其他用途。这就是为什么你的读取产生最后一次的值。但是,这是未定义的行为。运行valgrind应该精确定位错误的位置。

如果你想知道“它怎么可能”,这里有great answer解释在非常类似的情况下会发生什么。