我的程序跳过了一个返回语句。

5

我的程序有这个函数:

    vector<itemPtr> Level::getItemsAt(const Point& pt)
    {
        vector<itemPtr> vect(items.size());
        // copy all items at pt's position to vect
        remove_copy_if(items.begin(), items.end(), vect.begin(),
                       boost::bind(matchesPosition<itemPtr>, _1, pt));

        // update LevelMap and return
        map.setHasItem(pt, false);
        return vect;
    }

这段代码编译没有问题(我使用的是g++,gcc版本为4:4.4.1-1ubuntu2),但是当我运行程序时,它直接跳过了return语句。我使用gdb逐步调试,在前一行设置了断点,得到了以下结果:
Breakpoint 1, yarl::level::Level::getItemsAt (this=0x80d4d58, pt=...)
at src/Level.cpp:519
519                 map.setHasItem(pt, false);
(gdb) next
521             }
(gdb) 

我已经尝试多次从头重新编译,事先擦除可执行文件和所有对象文件,但它仍然会这样做。
奇怪的是,如果我注释掉return语句并尝试编译,它只会给出“warning: no return statement in function returning non-void”的警告。我本以为在一个返回值的函数中不提供return语句将是编译器错误,但我想可能不是这样。
我意识到这不足以让人理解,但有人知道为什么会发生这种情况吗?要检查什么?此时我甚至不知道从哪里开始查找。
编辑:为了澄清,我正在使用-O0进行编译。
根据tjm的说法,即使使用-O0编译器标志,我的gcc版本仍将使用RVO,所以那就是问题所在。谢谢你们的帮助。

6
你是否在编译时没有加上优化参数(-O0)?如果没有,那么这可能是“命名返回值优化”(Named Return Value Optimization)的一个实例。 - Philipp
是的,我用-O0编译了。我会把它加到问题里。 - Max
3个回答

6
只要行为保持不变,C++源代码不必与生成的目标代码一一对应。这里发生的是编译器重新排列代码,并可能调用返回值优化

编辑:

-fdump-tree-nrv添加到GCC选项中以查看编译器对NRVO的应用(您将获得一个带有.nrv扩展名的文件)。这仅适用于优化级别大于-O0
没有优化,用复制构造函数或复制赋值运算符调用替换return语句仍然是C ++前端转换,这不会被gdb优雅地处理。

1
我正在使用“-O0”进行编译。 - Max
1
@Max,我对RVO不是很了解,但如果Nikolai链接中的第一个示例是验证是否发生这种情况的有效测试,当我在这里编译它时,似乎即使您使用-O0编译,gcc 4.4.4也会这样做。 - tjm
@tjm:有趣。所以看起来gcc无论是否使用-O0,都会使用RVO。这可能回答了我的问题。@Nikolai:我使用了-fdump-tree-nrv编译并运行,但是我没有在任何地方看到.nrv文件。它去哪里了? - Max
它应该与源文件同名放在同一个目录下。它至少需要 -O1(没有优化标志意味着没有优化)。生成的文件难以阅读 :) - Nikolai Fetissov

1

我可以想到几个原因导致返回语句被跳过 - 以下哪些可能是原因之一?

  • 在第519行抛出了异常。考虑到第521行已经执行,这听起来非常不可能。
  • 编译器已经优化掉了返回语句 - 你是否在调试一个真正的调试版本(没有启用任何优化)?

函数是否正常工作 - 调用者是否能够得到结果并继续进行下一步操作?


我的程序在被调用者尝试使用函数返回的向量时崩溃。我原以为是因为我的程序试图使用一个空向量,但在函数调用后进行步进显示被调用者是一个正确大小的向量。这听起来像是返回值优化,但我正在使用O0 - Max

0

map和pt是正确分配和初始化的对象吗?

如果从第519行抛出异常,那么该方法将不会正常返回。在这种情况下,您可能希望在堆栈展开时下一行“执行”的代码是521行。

我在Visual C ++中看到了很多类似情况,当代码执行导致“未定义行为”时。我没有足够的g ++经验来知道观察到的行为是否相同。


没有抛出任何异常。我的程序在迭代通过该函数返回的向量后最终发生段错误。尽管这个问题似乎与被跳过的返回语句无关。 - Max

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接