在C ++中,当一个应该返回一个对象的函数没有return语句时会发生什么?什么回来了?
e.g。
std::string func() {}
答案 0 :(得分:28)
返回什么内容?
我们不知道。根据标准,行为未定义。
§6.6.3/2 The return statement [stmt.return]:
(强调我的)
在构造函数,析构函数或具有cv
void
返回类型的函数的末尾流动,相当于没有操作数的return
。否则,从main
(basic.start.main以外的函数的末尾流出会导致未定义的行为。
事实上,大多数编译器会给出警告,例如Clang:
警告:控制到达非空函数的末尾[-Wreturn-type]
答案 1 :(得分:7)
在C ++中,如果一个应该返回一个对象的函数在没有return语句的情况下结束会发生什么?
它会导致未定义的行为。没有人能分辨出究竟会发生什么。
答案 2 :(得分:5)
我很好奇,所以我在Visual C ++ 2015上做了一些测试。
int f()
{
if (false)
return 42;
// oops
}
int main()
{
int i = f();
}
我必须添加if
才能收到警告而非硬错误:
> cl /nologo /FAs /c a.cpp
a.cpp(6) : warning C4715: 'f': not all control paths return a value
生成的汇编代码非常简单,我删除了不相关的部分。这是f()
:
f:
xor eax, eax
je label
mov eax, 42
label:
ret
xor
行基本上是eax=0
。因为if (false)
是一个常量条件,所以生成的代码甚至不打算进行比较,然后无条件地跳转到label
,它只是从函数返回。您可以看到“返回值”(42
)实际上将存储在eax
中,但此行不会被执行。因此,eax == 0
。
以下是main()
的作用:
call f
mov _i$[ebp], eax
ret
它调用f()
并盲目地将eax
复制到堆栈中的某个位置(i
所在的位置)。因此,i == 0
。
让我们尝试使用对象和构造函数更复杂的东西:
struct S { int i=42; };
S f()
{
if (false)
return {};
// oops
}
int main()
{
S s = f();
}
main()
的作用基本上是保留sizeof(S)
个字节,将第一个字节的地址放在eax
中,然后调用f()
:
lea eax, _s$[ebp]
push eax
call f
同样,f()
将不会做任何事情,因为它将无条件地跳转到函数的末尾:
f:
xor eax, eax
je label
; some stuff
; call S::S(), which would set i to 42
; but none of that will happen
label:
ret
那么主要的sizeof(S)
字节发生了什么?他们从未改变过。它们包含该特定位置已经存在的内容。它们含有垃圾。
对于给定编译器的给定版本,这是一个未经优化的构建。更改编译器,更改行为。启用优化程序drastically change the behaviour。
不要这样做。