简体   繁体   中英

Checking my understanding about function return

As a newbie, I found it quite cryptic about the explanation of returning from function in C++ books.

Here is a summary of my understanding, hopefully someone can correct it:

Premises:

T foo() {
   ...
   return expr;
}

main() {
   T var = foo();
}

Is my below understanding about the returning process correct?

  1. The evaluation result of expr is implicitly converted to declared function return type T . This conversion happens within foo();
  2. The converted value above is used to initialize a temporary object, say "x". Sub-Question: Does this second conversion happen within foo() or main()?
  3. The temporary object "x" is used to initialize variable var within main().

Any input is welcome!

Let's approach this systematically.

If a function is declared as T f(); , and T is not void , and if the function returns normally, then it must return via a statement of the form return e; , where e is some expression.

When you evaluate the function-call expression f() , you obtain a value. Suppose U denotes an object type. If T = U & or T = U && , then the value is of type U , the expression e must be able to bind to the reference, and the return value is the value of e . (The return value is also a so-called "glvalue", in terms of its value category). Nothing else happens in this case. The value of the function call is the thing being returned.

However, when T = U , then the value of f() is a so-called "prvalue" (a "pure rvalue"), and this necessitates the construction of a temporary object of type U . This object is constructed as if by U obj = e (ie implicitly converted from the e ). The value of f() is then this temporary object. It may either be used to initialize yet another object (eg U x = f(); ), or it may be bound to a reference (eg U && r = f(); ).

The binding of the return expression e to the function-call value happens as the last thing inside the function body scope. Notably, this is before the end of the scope, ie before scope-local objects are destroyed. For example, if an exception is thrown during the construction of the return value object, scope unwinding has to happen to destroy local objects before the exception passes to the calling scope. Another useful illustration may be in the use of scoped guards, eg mutex locks:

U f()
{
    std::locK_guard<std::mutex> lock(state_mutex);
    return state.get_value();
}

Here we assume that the initialization U obj = state.get_value(); makes sense, and we assume further that state.get_value() must only be called while state_mutex is locked. The above code does this correctly and concisely.

  1. You are correct, the implicit conversion happens within foo . Consider when you have more than one return statement and each one returns a different type - all of those types must be converted before a value can be returned.
  2. There's no second conversion. The first conversion occurs as part of the construction or assignment of the temporary.
  3. Correct, except as explained below.

There's an optimization that many compilers will make called copy elision which skips the temporary altogether.

Your understanding is essentially correct.
There can be some optimizations, so that there are not that many steps of
copying. This can be either in the form of return value optimization or
in c++11 move semantics

Regarding your sub question;
You should make neither assumption, in say custom conversion operators, constructors
destructors, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM