2013-04-07 2 views
1
#include <string> 
#include <iostream> 

struct A 
{ 
    A(){} 

    A(const A&) 
    { 
     std::cout << "copy" << "\n"; 
    } 

    A& operator =(A) 
    { 
     return *this; 
    } 
}; 

int main() 
{ 
    A a; 
    A a2; 

    a=std::move(a2); 

    std::cin.ignore(); 

    return 1; 
} 

Похоже, что правило для копирования - это то, что аргумент должен быть значением prvalue, а не значением x, но почему?copy elision и rvalue

ответ

7

Похоже, что правило для копирования ellision состоит в том, что аргумент должен быть значением prvalue, а не значением x, но почему?

Ваша программа не содержит ситуаций, при которых может выполняться копирование/перемещение. C++ 11 Стандарт определяет именно эти ситуации в пункте 12.8/31:

При соблюдении определенных критериев, реализация может пропустить копирование/перемещение строительство объекта класса , даже если конструктор выбран для операции копирования/перемещения и/или деструктора для объекта имеют побочные эффекты. [...] Это элизия копирования/перемещения операций, называется копия элизия, допускается в следующих случаях (которые могут быть объединены, чтобы исключить несколько копий):

- в обратном заявлении в функции с возвращаемым типом класса, , когда выражение является именем энергонезависимого автоматического объекта (за исключением функции или параметра catch-clause) с тем же самым cv-unqualified в качестве возвращаемого типа функции, операция перемещения может быть опущена путем построения автоматического объекта непосредственно в возвращаемое значение функции

Это не ваша ситуация, потому что выражение return ed от вашего operator = равно *this, что не является именем объекта с автоматическим временем хранения. Кроме того, вы все равно не сохраняете результат operator =.

- в забрасываемом выражении, если операнд является именем энергонезависимого автоматического объекта (кроме функции или поймать-п параметра а), сфера не выходит за пределами конца внутренней ограждающих Try-блок (если есть один), операция копирования/перемещения от операнда к объекту исключения (15.1) можно опустить с помощью построения автоматического объекта непосредственно в объект исключения

Это не относится , потому что у вас нет выражения throw.

- когда временный объект класс, который не был связан с ссылкой (12.2) будут скопированы/перемещены к классу объекта с тем же CV-неквалифицированным типа, операция копирования/перемещения может быть пропущено Построив временный объект непосредственно в мишень опущенным копирования/перемещения

это не относится либо, потому что у вас нет временных объектов (xvalue не является временным).

- когда исключение-декларация обработчика исключений (раздел 15) объявляет объект того же типа в качестве объекта исключения (15.1) (для CV-квалификации, за исключением), операция копирования/перемещения может быть опущен , рассматривая объявление исключения как псевдоним для объекта исключения, если значение программы не изменится, за исключением выполнения конструкторов и деструкторов для объекта, объявленного описанием исключения.

В коде отсутствует обработчик исключений, поэтому эта ситуация также не применяется.


Если намеченная вопрос: «Почему вещи так, как они есть?», нет никаких объективных, исчерпывающий ответ, что я могу предоставить (хотя другие могли бы). Но я попытаюсь привести некоторые правдоподобные аргументы.

Как указано в параграфе Стандарта, приведенного выше, копия elision в случае оператора return означает, что функции разрешено строить объект, возвращаемый непосредственно в назначенный объект.

В частности, это означает, что компилятор может создавать код для этой функции, которая работает непосредственно на объекте, к которому возвращаемое значение должно быть назначено, и что живет вне стека фрейме запущенной функции, а не на локальный объект с автоматическим временем хранения выделен внутри фрейм стека функции. Это означает, что вы можете видеть локальный объект как псевдоним для назначенного.

Однако здесь у вас есть очень разные объекты, как материальные, так и требующие памяти и предназначенные для двух разных адресов. Невозможно применить трюк, подобный описанному ранее, потому что для такого рода псевдонимов потребуется изменение адреса объекта во время выполнения программы - и это незаконно.