当C ++引用离开其范围时会发生什么?

时间:2010-06-22 22:22:53

标签: c++

如果我正确地解释C ++引用,它们就像指针一样,但保证数据完整性(没有NULL,没有(int *)0x12345)。但是当引用对象的范围被遗漏时会发生什么?如果没有涉及魔法(可能不是),引用的对象将在我背后被摧毁。

我写了一段代码来检查:

#include <iostream>
using namespace std;

class A {
public:
        A(int k) { _k = k; };
        int get() { return _k; };
        int _k;
};

class B {
public:
        B(A& a) : _a(a) {}
        void b() { cout << _a.get(); }
        A& _a;
};

B* f() {
        A a(10);
        return new B(a);
}

int main() {
        f()->b();
}

放入_k实例变量来检查堆栈帧是否存在。

令人惊讶的是,它不是段错误而是正确打印'10',而我认为A在堆栈上分配,f()的堆栈帧将被至少cout<<覆盖调用

2 个答案:

答案 0 :(得分:27)

这是未定义的行为,您很幸运,a的内存尚未用于其他任何内容。在更复杂的情况下,你几乎肯定会得到垃圾。在我的机器上,我使用此代码获得随机垃圾。对我来说,这可能是因为我使用的是64位机器,它使用寄存器调用约定。寄存器比主存储器更频繁地重复使用(理想情况下......)。

所以回答你的“发生了什么”的问题。那么在这种情况下,引用可能只是一个有限指针和更友好的语法:-)。在引擎盖下,存储a的地址。稍后a对象超出了范围,但B对象对a的引用不会“自动神奇地”更新以反映这一点。因此,您现在有一个无效的引用。

使用这个无效的引用几乎可以产生任何事情,有时候会崩溃,有时只会产生双层数据。


编辑:感谢Omnifarious,我一直在考虑这个问题。 c ++中有一条规则,基本上说如果你有一个临时的const引用,那么临时的生命周期至少和const引用一样长。这引入了一个新问题。

编辑:针对感兴趣的人(const reference to temporary oddity)移动到单独的问题

答案 1 :(得分:6)

在C ++语言中,引用所绑定的对象的生命周期与引用本身的生命周期没有任何关系,只有一个例外(见下文)。

如果在引用之前销毁对象,则引用变为无效(如悬挂指针)。任何访问该引用的尝试都会导致未定义的行为。这就是你的例子中发生的事情。

引用在对象之前结束它的生命周期,然后......好吧,没有任何反应。引用消失,对象继续存在。

我上面讨论的唯一例外是使用直接临时对象初始化const引用。在这种情况下,临时对象的生命周期与引用的生命周期相关联。当引用死亡时,对象随之死亡

{
   const std::string& str = "Hello!"; 
   // A temporary `std::string` object is created here...
   ...
   // ... and it lives as long as the reference lives
   ...
} // ... and it dies here, together with the reference

P.S。您错误地使用了术语范围范围是标识符的可见区域。范围本身与对象生命周期无关。当某些东西“留下范围”时,通常情况下某些东西不会被破坏。使用“叶子范围”措辞来引用对象的破坏点是一种流行的误解。