0

我不明白这段代码是如何工作的:

class AAA {
public:
    short a, b;
};

AAA &getRef() {
    AAA aaa = {2, 6};
    return aaa;
} // 'aaa' is destroyed here right?

int main() {
    AAA &ref = getRef();
    cout << ref.a << ", " << ref.b << endl;

    cin.ignore();
    return 0;
}

ref.a尝试访问and不应该有错误ref.b吗?当我使用指针时,我也没有收到错误。我的意思是,这每次都会打印“2, 6” 。

编辑:是因为内存仍然设置为这些数字吗?

4

4 回答 4

7

它“有效”是因为函数返回时内存aaa没有被覆盖。如果您修改AAA类以具有修改aand的析构函数b,或者如果您使用一些写入堆栈的代码,它几乎肯定会覆盖这些值。

C++ 标准将返回对局部变量的引用定义为“未定义行为”。标准通常会在某些情况下执行此操作,例如,很难确定该值确实是基于堆栈的。

例如,考虑:

class BBB
{
   AAA& x;
  public:
   BBB(AAA& a) : x(a) {}
   AAA& getX() { return x; }
};

AAA& getReg()
{
   AAA aaa = { 2, 6}
   BBB bbb(aaa);
   return bbb.getX();
}

大多数现代编译器都会针对您所拥有的场景发出警告,有些可能还会针对我刚刚编写的代码发出警告。但是几乎可以肯定的是,对于无法诊断此“错误”的情况,可以提出一些更复杂的情况。

于 2013-09-16T22:30:51.720 回答
5

不幸的是,这是调用未定义行为的非法代码,但编译器不会将其标记为错误(尽管如果启用了更多编译器诊断,它可能会)。

它碰巧工作,大概是因为创建对象的内存位置没有被重新用于其他任何东西,也没有被清除或覆盖,所以你只是“幸运”的值,一旦放在那里,仍然存在。

于 2013-09-16T22:27:19.607 回答
2

看来您想要“证明”它可能会失败。也许尝试:

int main() {
    AAA &ref = getRef();
    cout << "Hello, world!" << endl;
    cout << ref.a << ", " << ref.b << endl;
}

此外,您应该启用并注意编译器的警告。

于 2013-09-16T22:31:24.563 回答
1

shorts 替换为具有复杂析构函数(如string)的用户定义类型,您可能会看到此崩溃。因为内存已被回收,但旧值仍然存在,所以即使在销毁后,您也可以(有时)看到内置类型(如 、 等)的intshort

[示例代码]

于 2013-09-16T22:32:09.583 回答