2010-02-07 65 views
1

我与C++和const引用鬼混,并感到困惑,为什么此代码的工作:为什么这个有效?返回在C++常量引用

#include <iostream> 

class A { 
public: 
    A() : a_(50) {} 
    const int& getA() const { return a_; } 
private: 
    const int a_; 
}; 

int main(int argc, char* argv[]) 
{ 
    A* a = new A(); 
    const int& var = a->getA(); 
    std::cout << var << std::endl; 
    delete a; 
    std::cout << var << std::endl; 
} 

结果:

50 
50 

这里是我的想法:

变种存储对a_的引用。
当a被删除时,a_也应该被删除。
当var被再次访问时,它不再包含有效的引用并且应该发生段错误。

为什么这样吗?我不相信我做了一个临时副本。

回答

13

一旦你删除a,访问var成为你进入未定义行为的大门。

这是偶然的“工作”。 var所指的空间不再是你的空间,而是这次访问它的空间。它可能导致分段错误,返回50以外的数字,或重新格式化硬盘。

请记住,似乎工作是一种可能的方式未定义的行为可以体现自己。

+0

这是我最好的猜测 - 它在这种情况下工作,但它有未定义的行为。绝对不能保证工作,而且非常危险。 – devillighter 2010-02-07 18:40:15

+0

最糟糕的是 - 在调试/发布和单核/双核CPU上表现不同的错误之一 – 2010-02-07 18:54:07

3

删除对象不会清除内存。直到内存用于别的东西时,该值仍然存在。所以它可能会工作一段时间....

一些C++实现有一个“调试模式”,设置一个特定的值到所有删除的内存来检测这样的错误。

2

当你删除一个你正在释放的内存,并允许后者新的覆盖它。在此之前,被删除对象中的所有变量仍然在内存中,但可能随时被覆盖。

1

由于const关键字,这非常棘手。

确实,在这种情况下,您可能正在读取未初始化的内存。对一些想法:

  1. 您没有使用调试模式:这通常不是一个好主意,只要代码没有经过测试,但它留下两个选择:
    • 发布模式内存管理器不会覆盖内存,所以你访问最后一个已知的地址,这仍然是偶然的工作
    • 或整个操作完全优化了,因为编译器知道你没有改变的值,它不能改变(尽管由于C++中const常量的限制,这可能不是真的)
  2. 你在调试模式,但优化激活,所以同样的观点也适用
  3. _a的内容,因为标 const不是堆分配,也不堆栈中分配,但驻留在应用程序的 DATA部分,所以参考可能确实仍然有效,不仅是偶然的。 [编辑]:这只适用于static const变量。

您可能会考虑编写自定义内存管理器或研究编译器的调试模式行为,因为这非常非常重要。例如,Visual Studio将设置变量为0xCDCDCDCD。您还会在数组末尾找到有趣的值,例如0xDEADC0DE

+0

关于(3),'_a'可能在“DATA部分”中的唯一方法是编译器执行广泛的静态分析,并确定只有1个“A”的实例,在这种情况下,整个对象将在那里。一个'const'成员仍然占用一个对象的每个实例的空间。 – 2010-02-07 19:21:56

+0

非常真实...相应地编辑了我的答案。谢谢你纠正我。 – mnemosyn 2010-02-07 21:19:52

+0

是的,我想知道你是否在考虑静态常量。 +1。 – 2010-02-09 10:32:37