Я возвращаю неназванный объект из функции. Почему РВО все еще срабатывает?

Относительно этого: Почему std::move предотвращает RVO? кто-то написал, что: "Следовательно в операторе возврата исключение копии может произойти только в том случае, если выражение является именем локальной переменной"

Однако я сделал небольшой тест с GCC:

class X
{
public:
    X()
    {
        cout << "def" << endl;
    }
    X(const X& x)
    {
        cout << "copy" << endl;
    }
    X(X&& x)
    {
        cout << "move" << endl;
    }
};

X produceX()
{
    return X();
}

int main()
{
    X x{produceX()};
    return 0;
}

Функция productX не возвращает именованное значение. Он возвращает безымянный временный объект. Однако RVO по-прежнему работает, и нет конструкции копирования или перемещения. Объект x из main создается на месте. Если я напишу productX следующим образом:

X produceX()
{
    X localNamedObject;
    return localNamedObject;
}

он ведет себя так же (что и ожидается). Но почему в первом случае допускается РВО?


person rubix_addict    schedule 11.12.2014    source источник
comment
Это разрешено, потому что стандарт C++ говорит, что это разрешено. Переменная не должна называться. Цитата либо некорректна, либо вырвана из контекста.   -  person juanchopanza    schedule 11.12.2014
comment
Следовательно, в операторе return исключение копирования может произойти только в том случае, если выражение имени локальной переменной не соответствует действительности.   -  person Jonathan Wakely    schedule 11.12.2014


Ответы (2)


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

Копирование разрешено при возврате временного объекта (как общий случай использования временного объекта для инициализации объекта того же типа), а также при возврате локальной переменной.

Это также разрешено при генерации и перехвате исключений по значению, но это выходит за рамки этого вопроса.

person Mike Seymour    schedule 11.12.2014
comment
Может ли кто-нибудь указать на конкретное предложение в Стандарте, в котором говорится, что RVO может применяться при возврате временного объекта? Кроме того, означает ли это, что std::move не предотвращает RVO, и они были неправы? - person rubix_addict; 11.12.2014
comment
@rubix_addict: Это ответ, из которого вы взяли эту цитату. C++11 [class.copy] 12.8/31, третий пункт. - person Mike Seymour; 11.12.2014
comment
Кроме того, означает ли это, что std::move не предотвращает RVO - нет, условие состоит в том, что временный объект класса... будет скопирован/перемещен. Результатом std::move является ссылка, а не временный объект, поэтому исключение не применяется. - person Mike Seymour; 11.12.2014

RVO расшифровывается как «оптимизация возвращаемого значения» и относится к методу построения результата возвращаемого выражения непосредственно в пространстве возвращаемого значения. Он применяется, когда возвращаемое выражение является значением rvalue.

NRVO означает «оптимизация именованного возвращаемого значения» и относится к методу создания именованного объекта, который в конечном итоге будет возвращен непосредственно в пространстве возвращаемого значения. Он применяется, когда возвращаемое выражение является lvalue.

person Sebastian Redl    schedule 11.12.2014