Why cant copy elision take place when a 'by-value' parameter is also the 'by-value' return argument?

79 views Asked by At

In the following code snippet my function tries to return it's 'by-value' argument as a 'by-value' return-value. I watched a video where it stated: "It is physically not possible to do copy elision here.." but I dont see why the we couldn't use the same memory address for the function parameter as well as the return value.

std::string foo(std::string s){
    return s;
}

I tried to understand it by watching a video but can't see where this would fail to do copy elision.

1

There are 1 answers

0
Jan Schultke On

Regardless of who is in charge of destroying function arguments, they cannot also be the result object created at the call site. This is required by C++17, and would be difficult/impossible to implement with NRVO(1) for function parameters. Consider this function and call:

std::string foo(std::string s);

std::string r = foo("...");

What happens is:

  1. a std::string s argument is constructed from "..."
  2. control is transferred into the function, and the function does its work
  3. in an implementation-defined order(2):
    • control is transferred back to the caller
    • the function argument is destroyed by whoever has control

If the caller is in charge of destroying s, how is the caller supposed to know that r is the same object as s? It's impossible to know without looking inside the definition of foo, or it would need to get additional run-time information that informs it about which parameter (if any) is the same object as the result object.

If the callee is in charge of destroying s, that would mean that r cannot be s because s is destroyed by foo.


(1) NRVO means Named Return Value Optimization.

(2) The relevant wording for step 3 is in [expr.call] p6:

It is implementation-defined whether the lifetime of a parameter ends when the function in which it is defined returns or at the end of the enclosing full-expression. The initialization and destruction of each parameter occurs within the context of the full-expression where the function call appears.