Какая структура функций лучше?

Посмотрите на следующий код:

class MyClass{
public:
    MyClass(){}
    MyClass(MyClass &&){}
    MyClass(const MyClass &){}
};
MyClass f1(){
    MyClass &&o=MyClass();
    /*...*/
    return std::move(o);//or return static_cast<MyClass &&>(o);
}
MyClass f2(){
    MyClass o=MyClass();
    /*...*/
    return o;
}


int main(int, char **){
    auto a=f1();
    auto b=f2();
}

функция f2 это нормальная форма возврата объекта. NRVO может применяться, и можно избежать дополнительного вызова конструктора копирования. f1 это новая форма, которая использует ссылку rvalue. Для систем, которые не поддерживают NRVO, но поддерживают ссылку на rvalue, вызывается конструктор перемещения, а не конструктор копирования, что в большинстве случаев считается лучшим.

Проблема f1 это: есть ли компиляторы, которые поддерживают NRVO в этом случае? В конце концов, это, кажется, лучшая форма в будущем.

2 ответа

Решение

Вот как работают текущие компиляторы (магистраль MSVC10 / gcc):
Предполагая, что MyClass является подвижным

f1 : move   
f2 :   
worst case : move 
best case : NRVO 

Предполагая, что MyClass не может быть перемещен:

f1 : copy    
f2 :    
worst case : copy    
best case : NRVO 

Поэтому, даже если компиляторы становятся лучше и начинают выполнять NRVO для таких функций, как f1, зачем усложнять код, когда классические функции C++03 уже оптимальны?

есть ли поддержка компилятора NRVO в этом случае?

Определить "поддержку компилятора"?

Какие f1 делает полностью разрушить способность компилятора оптимизировать копию MyClass, Давайте посмотрим на f1 в деталях

MyClass &&o=MyClass();

Это создает временную, а не переменную стека. Затем этот временный объект связан со ссылкой на r-значение, называемой o, который продлевает время жизни временного до конца функции.

return std::move(o); //or return static_cast<MyClass &&>(o);

Это возвращает ссылку на r-значение привязанной к стеку ссылки на r-значение для временного объекта. И поскольку вы возвращаете значение, а не ссылку, компилятор должен создать из него временное значение.

Копирование / перемещение временного в a будет исключен. Но вы все равно создали два временных (исходное и возвращаемое значение).

Так f1 делает следующее:

create temporary
copy/move from temporary to return value
elide copy/move from return value to `a`.

f2 делает:

create stack variable
elide copy/move from stack variable to `b`.

Если NVRO не существует, у вас есть:

create stack variable
copy/move from stack variable to return value
elide copy/move from stack variable to `b`.

Так, f2 в худшем случае равен f1, И более чем вероятно, лучше.

Пожалуйста, перестаньте пытаться перехитрить компилятор. Просто позвольте копии elision делать свою работу.

Другие вопросы по тегам