当返回值丢失时,C++ 代码行为异常

c++ code behaves abnormally when the return value is missing

本文关键字:代码 异常 C++ 返回值      更新时间:2023-10-16

GCC 9.2.1 给出了一个警告,指出"函数中没有返回语句返回非 void",但是,代码确实可以编译(我用标志 -O3 和 -finline-functions 编译(。

我希望程序没有输出,因为 while 循环的条件计算结果应为 false。但是,我从程序中获得了以下输出(打印在 while 循环中(:

"it != mMap.end((: 0">

输出特别奇怪,因为打印的值(即 0 或"false"(也是 while 循环的条件。

打印后,程序出现段错误,因为迭代器变得无效(通过 while 循环中的it++,而这不应该执行(。

我想这一切都可以归结为缺少的返回值。但是,我发现令人惊讶的是,代码的行为如此病态,仅仅是因为没有提供返回值。我希望

能深入了解正在发生的事情。
#include <iostream>
#include <tr1/unordered_map>
struct Test
{
int Dummy (void) const
{
std::tr1::unordered_map<int, int>::const_iterator it = mMap.begin();
while (it != mMap.end())
{   
std::cout << "it != mMap.end(): " << (it != mMap.end()) << std::endl;
it++;
}   
}
std::tr1::unordered_map<int, int> mMap;
};
int main (void)
{
Test test;
test.Dummy();
return 0;
}

从非void函数返回而不提供返回值是欠精细的行为,因此编译器可以做任何它想做的事情。

编译器在这种情况下所做的特别是,它发现跳过循环会触发 UB,因此假设循环至少进入一次。因此,它假设它可以安全地进入循环而无需检查条件,因为编译器相信程序的作者没有调用任何未定义的行为。

这当然是我的猜测。

您应该使用-Wextra打开警告,并在gcc-Wall,例如启用警告Control reaches the end of a non-void function,这样您就不会忘记修复这样的东西。要强制执行它,请启用编译器标志-Werror

不返回值会调用未定义的行为,因此如果函数返回,编译器可以返回垃圾值或使程序崩溃(这是clang通常所做的(。这很糟糕,你永远不应该像那样保留损坏的代码。为了获得更多见解,您可以使用反汇编器并查看编译器在函数结束时做了什么。