【问题标题】:Why does returning a reference to a automatic variable work?为什么返回对自动变量的引用有效?
【发布时间】:2013-08-26 21:46:07
【问题描述】:

我目前正在阅读有关 C++ 的内容,并且我读到在使用按引用返回时,我应该确保我没有返回对将超出范围的变量的引用函数返回。

那么为什么在Add 函数中对象cen 是通过引用返回的,并且代码可以正常工作?!

代码如下:

#include <iostream>
using namespace std;

class Cents
{
 private:
 int m_nCents;

 public:
 Cents(int nCents) { m_nCents = nCents; }

int GetCents() { return m_nCents; }
};

Cents& Add(Cents &c1, Cents &c2)
{
   Cents cen(c1.GetCents() + c2.GetCents());
   return cen;
}

int main()
{
   Cents cCents1(3);
   Cents cCents2(9);
   cout << "I have " << Add(cCents1, cCents2).GetCents() << " cents." << std::endl;

   return 0;
}

我在 Win7 上使用 CodeBlocks IDE。

【问题讨论】:

  • 因为它是未定义的行为,它看起来可以正常工作,但稍后会中断,不能依赖它。
  • 可能发生的事情(同样,对于 UB,任何事情都会发生)是因为在你调用 Add 之后,你没有调用其他任何东西,还没有任何东西覆盖 @987654325 所在的那块内存@ 是,所以旧值仍然存在。话虽如此,你不能依赖这种情况总是发生。
  • 这两个 cmets 应该都是答案
  • 通常会在堆栈再次增长时被覆盖。调用 Factorial(50) 的递归实现,当你使用它时我最好它会死
  • @DanF 好的,我会回答的。

标签: c++ reference return undefined-behavior


【解决方案1】:

这是undefined behavior,它可能看起来工作正常,但它随时可能中断,你不能依赖这个程序的结果。

当函数退出时,用于保存自动变量的内存将被释放,引用该内存将无效。

3.7.3 部分中的 C++ 标准草案 第 1 段 说:

显式声明的块范围变量 register 或未显式声明的 static 或 extern 具有自动存储持续时间。 这些实体的存储将持续到创建它们的块退出。

【讨论】:

    【解决方案2】:

    可能发生的事情(同样,对于 UB,任何事情都会发生)是因为在您调用 Add 之后,您没有调用其他任何东西,还没有任何东西覆盖 cen 所在的内存,所以旧值仍然存在。话虽这么说,你不能指望这种情况总是发生。

    【讨论】:

    • 正如@GaryWalker 在他的评论中所说,在Add 之间调用任何使用大量堆栈的东西并将其打印出来;你几乎肯定会得到垃圾。
    • 实际上,在尝试使用悬空引用之后,您根本无法依赖任何东西。
    【解决方案3】:

    您应该执行 memcpy 以将返回的对象复制到堆中。尽管代码有效,但返回超出范围的对象时行为未定义。当代码很小的时候它可能总是有效的,因为当函数返回时,函数占用的堆栈部分不会被清除,并且由于函数内的局部变量将在那里分配空间,所以你得到的值(通常) 包含您期望的值。但是当你有多个函数互相调用并且程序变大时,你的程序将开始产生未定义的行为。有时甚至可能出现段错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      • 2015-08-30
      • 2017-08-05
      • 1970-01-01
      • 2018-09-11
      相关资源
      最近更新 更多