【问题标题】:Overloading << operator and recursion重载 << 运算符和递归
【发布时间】:2011-01-22 06:05:00
【问题描述】:

我尝试了以下代码:

#include <iostream>
using std::cout;
using std::ostream;

class X
{
public:
    friend ostream& operator<<(ostream &os, const X& obj) 
    {
        cout << "hehe";          // comment this and infinite loop is gone
        return (os << obj);
    }
};

int main()
{
    X x;
    cout << x;
    return 0;
}

当我编译并运行它时,它符合预期;一个无限循环。如果我删除友元函数中的cout 语句,则不会发生递归。为什么会这样?

【问题讨论】:

  • 顺便说一句,我正在使用 MinGW(Minimalist GNU for Windows)。
  • 您如何注意到没有发生递归?它是否正确结束程序?还是它只是不打印任何东西而您必须终止它? (请注意,尾递归可能会使您不会收到堆栈溢出)。
  • @litb:它立即退回到终端(我没有按一个键来终止进程)。
  • @litb:我尝试通过gdb 运行二进制文件,它显示SIGSEGV :) 感谢您的评论,也许您应该将其写为答案!它因堆栈溢出而崩溃!!耶!
  • 作为堆栈溢出的这个问题,我认为它绝对应该去meta。

标签: c++ recursion operator-overloading cout ostream


【解决方案1】:

优化器确定您所有剩余的活动都无效并将其优化掉。 是对是错是另一回事。

特别是:

X x;

创建空对象“x”

cout << x;

来电:

return (os << obj);

追加空对象;编译器注意到 'os' 自上次调用以来没有增长,并且没有显示进一步这样做的承诺(并且没有其他任何事情发生),因此它决定整个业务是多余的并且可以在此时截断。

万一你打电话

    cout << "hehe";          // comment this and infinite loop is gone

有一些额外的活动,所以优化器不会删除以下调用。

我想如果你用任何非空的东西初始化x,或者执行除cout &lt;&lt; "hehe"; 之外的任何非空活动,你的递归运行也是一样的。

【讨论】:

  • 实际上我认为如果标准指定无限递归导致“未定义的行为”,优化器将是完全正确的;在这种情况下,什么都不做就可以了。我在网上找不到 C++ 标准的副本,有它的人可以检查一下吗?
  • ...关于无关的注释,我想知道如果调用包含在try-catch(...) 中以捕获堆栈溢出异常会怎样。我认为这几乎是预期的行为,如果我错了,请纠正我。
  • 我不认为这样的异常(顺便说一句,这不是 C++ 异常,但它是 *NIX 上的某种信号和 Windows 上的 SEH 异常)可以被捕获。实际上,当堆栈溢出时,您无能为力:一切都已经疯了。如果您注意到,进入堆栈溢出的 Windows 应用程序甚至不会显示错误消息,因为现在没有更多堆栈了,它们无法执行任何操作。
【解决方案2】:

在这两种情况下(有和没有写“hehe”)Visual Studio 2005 都会给出以下警告:

warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow

在这两种情况下它都会编译并且在这两种情况下都会导致堆栈溢出。

但是,如果没有“呵呵”,堆栈溢出会更快发生。

【讨论】:

  • 你说得对,帕特里克,谢谢!并且感谢 litb 怀疑我认为递归不会发生的结论的有效性,这让我通过gdb 运行它,现在我很高兴看到SIGSEGV 这证明在这两种情况下都会发生递归:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 2020-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多