Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's happening in this return statement?

Tags:

c++

stl

I'm reading on copy elision (and how it's supposed to be guaranteed in C++17) and this got me a bit confused (I'm not sure I know things I thought I knew before). So here's a minimal test case:

std::string nameof(int param)
{
    switch (param)
    {
    case 1: 
        return "1"; // A
    case 2: 
        return "2" // B
    }
    return std::string(); // C
}

The way I see it, cases A and B perform a direct construction on the return value so copy elision has no meaning here, while case C cannot perform copy elision because there are multiple return paths. Are these assumptions correct?

Also, I'd like to know if

  • there's a better way of writing the above (e.g. have a std::string retval; and always return that one or write cases A and B as return string("1") etc)
  • there's any move happening, for example "1" is a temporary but I'm assuming it's being used as a parameter for the constructor of std::string
  • there are optimization concerns I ommited (e.g. I believe C could be written as return{}, would that be a better choice?)
like image 624
Lorah Attkins Avatar asked Jan 18 '17 21:01

Lorah Attkins


2 Answers

To make it NRVO-friendly, you should always return the same object. The value of the object might be different, but the object should be the same.

However, following above rule makes program harder to read, and often one should opt for readability over unnoticeable performance improvement. Since std::string has a move constructor defined, the difference between moving a pointer and a length and not doing so would be so tiny that I see no way of actually noticing this in the application.

As for your last question, return std::string() and return {} would be exactly the same.

There are also some incorrect statements in your question. For example, "1" is not a temporary. It's a string literal. Temporary is created from this literal.

Last, but not least, mandatory C++17 copy elision does not apply here. It is reserved for cases like

std::string x = "X";

which before the mandatory requirement could generate code to create a temporary std::string and initialize x with copy (or move) constructor.

like image 116
SergeyA Avatar answered Oct 28 '22 15:10

SergeyA


In all cases, the copy might or might not be elided. Consider:

std::string j = nameof(whatever);

This could be implemented one of two ways:

  1. Only one std::string object is ever constructed, j. (The copy is elided.)

  2. A temporary std::string object is constructed, its value is copied to j, then the temporary is destroyed. (The function returns a temporary that is copied.)

like image 32
David Schwartz Avatar answered Oct 28 '22 16:10

David Schwartz