0

The following compiles and works as expected:

std::unique_ptr<char> input_to_char_array()
{
    std::unique_ptr<char> c;
    c.reset(new char('b'));
    // c[1].reset(new char[20]());

    return c;
}

But this doesn't:

std::unique_ptr<char> input_to_char_array()
{
    std::unique_ptr<char> c[2];
    c[0].reset(new char('b'));
    c[1].reset(new char('a'));

    return c[0]; // is this considered "return statement's expression is the name of a non-volatile object with automatic storage duration"
}

g++ outputs:error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = char; _Dp = std::default_delete<char>]

From some SO research Returning unique_ptr from functions and Why can't I return a unique_ptr from a pair? it seems that this is all related to copy elision and named return value optimization.

Can someone confirm if my guess is correct. If so, what exactly is the criteria for copy elison so that NRVO can be applied?

Community
  • 1
  • 1
Rich
  • 1,669
  • 2
  • 19
  • 32
  • 3
    It says it in the answer to the very question you reference, does it not? `This elision of copy/move operations, called copy elision, is permitted [...] in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type` – Taekahn Jul 14 '15 at 06:18
  • @Taekahn isn't c[0] the name of the automatic object? – Rich Jul 14 '15 at 06:20
  • 2
    `c[0]` is an expression, not a name. – Sneftel Jul 14 '15 at 06:22
  • confused.. what exactly is a name? An identifier that denotes an object? – Rich Jul 14 '15 at 06:25
  • 1
    The idea behind NRVO is that it can be implemented in the compiler by adding an additional parameter to the function. This parameter describes the memory location at which to construct the return value. In the first example, the object `c` would directly be constructed at this location, and the return statement becomes a no-op. In the second example, it isn't possible to construct the return value at this memory location, since `c` is larger (in size) than the return value. – dyp Jul 14 '15 at 07:18
  • But this isn't the only reason it won't work here: NRVO changes the observable behaviour but isn't mandatory, so it has been restricted to very few cases. For example, in the first code block, `return *&c;` prevents NRVO, despite the function having the same behaviour in every other respect. – dyp Jul 14 '15 at 07:21
  • @LokiAstari The return value is treated as an rvalue iff copy/move elision *could* apply (minus some relaxations). So we need to determine whether or not copy/move elision could apply, then we know which constructor (copy or move) will be used. – dyp Jul 14 '15 at 09:42
  • @dyp: OK. Learn something new every day. – Martin York Jul 14 '15 at 09:44

0 Answers0