2017-01-18 2 views
6

Я читаю о копировании elision (и как это должно быть гарантировано на C++ 17), и это немного меня смутило (я не уверен, что знаю вещи, которые, как я думал, знал раньше). Так вот минимальный тест:Что происходит в этом возвращении?

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

Как я вижу это, случаи А и Б выполнить прямое строительство на возвращаемом значении, поэтому скопируйте элизию не имеет никакого значения здесь, в то время как случай C не может выполнять копирование Пропуска, потому что есть несколько обратных путей. Правильно ли эти допущения?

Кроме того, я хотел бы знать, если

  • есть лучший способ написания выше (например, имеют std::string retval; и всегда возвращаются, что один или писать случаи A и B в return string("1") и т.д.)
  • происходит какое-то движение, например "1" является временным, но я предполагаю, что он используется в качестве параметра для конструктора std::string
  • есть проблемы с оптимизацией, которую я пропустил (например, я считаю, что C может быть записано как return{}, было бы лучше?)
+0

Почему вы думаете, случай А отличается от случая C. A эффективно 'станд :: строка ("1")' и 'С станд :: строка ("")' –

+0

@KerrekSB Nothing –

+0

@EdHeal Я считаю, что случай C должен быть эквивалентен 'std :: string (" 1 ")' copy elision должен произойти или нет никакой разницы от прямого построения в возвращаемом значении? Или множественные обратные пути возились с копией? Во всяком случае, это то, о чем я прошу, поэтому не спрашивайте меня. –

ответ

3

Чтобы сделать его NRVO-дружественным, вы всегда должны возвращать тот же объект. Значение объекта может отличаться, но объект должен быть одинаковым.

Однако в соответствии с вышеприведенным правилом программа усложняется для чтения, и часто следует выбирать читаемость в отношении незаметного повышения производительности. Поскольку std::string имеет определенный конструктор перемещения, разница между перемещением указателя и длиной и невозможностью сделать это будет настолько крошечной, что я не вижу никакого способа заметить это в приложении.

Что касается вашего последнего вопроса, то return std::string() и return {} были бы такими же.

В вашем вопросе также есть некоторые неправильные утверждения. Например, "1" не является временным. Это строковый литерал. Временный создается из этого литерала.

Последнее, но не менее важное, обязательное C++ 17 copy elision здесь не применяется. Он зарезервирован для случаев, как

std::string x = "X"; 

который перед обязательным требованием может генерировать код, чтобы создать временный std::string и инициализировать x с копией (или переместить) конструктор.

1

Во всех случаях копия может быть или не удалена. Рассмотрим:

std::string j = nameof(whatever); 

Это может быть реализовано одним из двух способов:

  1. только один std::string объект когда-либо построенных, j. (Копия завершена.)

  2. Построен объект временного std::string, его значение копируется в j, после чего временное уничтожается. (Функция возвращает временное копирование.)

Смежные вопросы