What happens when a function that returns an object ends without a return statement

前端 未结 3 1490
走了就别回头了
走了就别回头了 2020-12-06 16:27

In C++, what happens when a function that is supposed to return an object ends without a return statement? What gets returned?

e.g.

std::string func         


        
相关标签:
3条回答
  • 2020-12-06 17:02

    What gets returned?

    We don't know. According to the standard, the behavior is undefined.

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

    (emphasis mine)

    Flowing off the end of a constructor, a destructor, or a function with a cv void return type is equivalent to a return with no operand. Otherwise, flowing off the end of a function other than main (basic.start.main) results in undefined behavior.

    In fact most compilers would give a warning for it, like Clang:

    warning: control reaches end of non-void function [-Wreturn-type]

    0 讨论(0)
  • 2020-12-06 17:18

    I was curious, so I made a few tests on Visual C++ 2015.

    int f()
    {
        if (false)
            return 42;
    
        // oops
    }
    
    int main()
    {
        int i = f();
    }
    

    I had to add the if to get a warning instead of a hard error:

    > cl /nologo /FAs /c a.cpp
    a.cpp(6) : warning C4715: 'f': not all control paths return a value
    

    The assembly code that's generated is pretty simple and I've removed the irrelevant parts. Here's the meat of f():

    f:
        xor eax, eax
        je label
        mov eax, 42
    label:
        ret
    

    The xor line is basically eax=0. Because if (false) is a constant condition, the generated code doesn't even bother to do a comparison and will then jump unconditionally to label, which just returns from the function. You can see that the "return value" (42) would actually be stored in eax, but that this line won't ever be executed. Therefore, eax == 0.

    Here's what main() does:

        call f
        mov _i$[ebp], eax
        ret
    

    It calls f() and blindly copies eax into a location on the stack (where i is). Therefore, i == 0.

    Let's try something more complicated with an object and a constructor:

    struct S { int i=42; };
    
    S f()
    {
        if (false)
            return {};
    
        // oops
    }
    
    int main()
    {
        S s = f();
    }
    

    What main() does is basically reserve sizeof(S) bytes on the stack, put the address of the first byte in eax and then call f():

        lea eax, _s$[ebp]
        push eax
        call f
    

    Again, f() won't do anything, as it will unconditionally jump to the end of the function:

    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
    

    So what happened to the sizeof(S) bytes in main? They were never changed. They contain whatever was already in memory at that particular location. They contain garbage.

    This is with an unoptimized build, on a given version of a given compiler. Change the compiler, change the behaviour. Enable the optimizer, drastically change the behaviour.

    Don't do it.

    0 讨论(0)
  • 2020-12-06 17:24

    In C++, what happens when a function that is supposed to return an object ends without a return statement?

    It causes undefined behavior. No one can tell what exactly will happen.

    0 讨论(0)
提交回复
热议问题