1

我在玩弄 C++ 和 const 引用,很困惑为什么这段代码有效:

#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

以下是我的想法:

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

为什么这行得通?我不相信我会制作临时副本。

4

4 回答 4

13

在您删除的那一刻a,访问var成为您进入未定义行为领域的大门。

这是偶然的“工作”。一个人所指的空间var不再是你的,但这次你成功地访问了它。它可能导致分段错误、返回 50 以外的数字或重新格式化您的硬盘驱动器。

请记住,似乎有效是未定义行为表现出来的一种可能方式。

于 2010-02-07T18:37:38.107 回答
3

删除对象不会清除内存。在内存用于其他用途之前,该值仍然存在。所以它可能会工作一段时间......

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

于 2010-02-07T18:40:13.973 回答
2

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

于 2010-02-07T18:41:02.563 回答
1

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

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

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

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

于 2010-02-07T18:51:20.590 回答