当返回对象的函数在没有return语句的情况下结束时会发生什么

时间:2016-08-24 08:36:11

标签: c++ function object return language-lawyer

在C ++中,当一个应该返回一个对象的函数没有return语句时会发生什么?什么回来了?

e.g。

std::string func() {}

3 个答案:

答案 0 :(得分:28)

  

返回什么内容?

我们不知道。根据标准,行为未定义。

§6.6.3/2 The return statement [stmt.return]

(强调我的)

  

在构造函数,析构函数或具有cv void返回类型的函数的末尾流动,相当于没有操作数的return。否则,从mainbasic.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

不要这样做。