Mat*_*son 16 c++ return function object language-lawyer
在C++中,当一个应该返回一个对象的函数在没有return语句的情况下结束时会发生什么?什么回来了?
例如
std::string func() {}
Run Code Online (Sandbox Code Playgroud)
son*_*yao 28
什么回来了?
我们不知道.根据标准,行为是不确定的.
(强调我的)
在构造函数,析构函数或具有cv
void
返回类型的函数的末尾流动,相当于return
没有操作数的函数.否则,流出除main
(basic.start.main)之外的函数的末尾会导致未定义的行为.
事实上,大多数编译器会给它一个警告,比如Clang:
警告:控制到达非空函数的末尾[-Wreturn-type]
在C++中,当一个应该返回一个对象的函数在没有return语句的情况下结束时会发生什么?
它会导致未定义的行为.没有人能分辨出究竟会发生什么.
我很好奇,所以我在Visual C++ 2015上做了一些测试.
int f()
{
if (false)
return 42;
// oops
}
int main()
{
int i = f();
}
Run Code Online (Sandbox Code Playgroud)
我不得不添加if
以获取警告而不是硬错误:
> cl /nologo /FAs /c a.cpp
a.cpp(6) : warning C4715: 'f': not all control paths return a value
Run Code Online (Sandbox Code Playgroud)
生成的汇编代码非常简单,我删除了不相关的部分.这是以下内容f()
:
f:
xor eax, eax
je label
mov eax, 42
label:
ret
Run Code Online (Sandbox Code Playgroud)
这xor
条线基本上是eax=0
.因为if (false)
是一个常量条件,所生成的代码甚至都不打算进行比较,然后无条件地跳转到label
,只是从函数返回.你可以看到"返回值"(42
)实际上会被存储eax
,但是这行不会被执行.因此,eax == 0
.
这是做什么的main()
:
call f
mov _i$[ebp], eax
ret
Run Code Online (Sandbox Code Playgroud)
它调用f()
并盲目地复制eax
到堆栈中的某个位置(在哪里i
).因此,i == 0
.
让我们尝试使用对象和构造函数更复杂的东西:
struct S { int i=42; };
S f()
{
if (false)
return {};
// oops
}
int main()
{
S s = f();
}
Run Code Online (Sandbox Code Playgroud)
main()
基本上什么是sizeof(S)
堆栈上的保留字节,将第一个字节的地址放入eax
然后调用f()
:
lea eax, _s$[ebp]
push eax
call f
Run Code Online (Sandbox Code Playgroud)
同样,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
Run Code Online (Sandbox Code Playgroud)
那么sizeof(S)
主要的字节发生了什么?他们从未改变过.它们包含该特定位置已经存在的内容.它们含有垃圾.
对于给定编译器的给定版本,这是一个未经优化的构建.更改编译器,更改行为.启用优化程序,彻底更改行为.
不要这样做.