2012-06-18 2 views
7

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

Например, у нас есть класс Foo, который имеет конструктор перемещения, и у нас есть функция, которая возвращает объект Foo.

Foo g() { 
    Foo f; 

    // do something with f 

    return f; 
} 

Если мы предполагаем, что нет RVO, конструктор перемещения, который, как предполагается, называется?

Обновление: Наверное, я не показывал свое намерение четко. Я просто хочу знать, что могу в худшем случае переместить объект, не скопированный. Либо RVO, либо NRVO случается, я счастлив. И я должен также сказать, что конструктор перемещения и назначение перемещения не удаляются и выполняются надлежащим образом.

+0

Да, локальные объекты в автоматическом хранилище неявно рассматриваются как значения xvalues ​​в операторах return. – ildjarn

+0

@ildjarn: Я думаю, что только если вы вернете его напрямую. Где-то на SO я был исправлен, сказав, что это переместило 'f' в функцию:' return do_something (f); '. – GManNickG

+0

@GManNickG: У меня не было времени на стандартное или оговорки, поэтому комментарий, а не ответ. Я думаю, ты прав. : -] – ildjarn

ответ

4

Да. См. [Класс.копировать] р32

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

+0

+1 для необходимой стандартной ссылки. – ildjarn

2

В этом случае, поскольку возвращаемое значение имеет имя (f), оно будет применяться к NRVO (с именем return value).

Таким образом, технический ответ, основанный только на формулировках, заключается в том, что отсутствие RVO не предотвратит копирование, поскольку NRVO все еще допускает его.

Против этого, я считаю, что выбор между перемещением/копией возвращаемого значения может/будет зависеть от определения Foo - есть определенные моменты, когда он будет скопирован вместо перемещения, например, если вы явно удалил конструктор перемещения и переместил операторы присваивания, или вы не определили конструкцию перемещения/присвоение, и он не может быть синтезирован неявно.

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

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

+0

Наверное, я не показал свое намерение четко в вопросе. Я просто хочу знать, что могу в худшем случае переместить объект, не скопированный. Либо RVO, либо NRVO случается, я счастлив. И я должен также сказать, что конструктор перемещения и назначение перемещения не удаляются. Благодарю. – haotang

+3

@Jerry: В этом коде есть две потенциальные копии. Первый - от локальной переменной до оператора return, который обычно называется (N) RVO. Это гарантировано, что не нужно копировать, если есть конструктор перемещения, компилятор может применить (N) RVO или нет, но если это не так, он должен * переместить конструкцию. Вторая потенциальная копия находится на стороне вызывающего абонента, из возвращаемого объекта и выходит за пределы области вопроса, так как она зависит от кода вызывающего абонента, а не от функции. –

1

Правило в том, что всякий раз, когда разрешение копирования разрешено, но не возникает, конструктор перемещения будет использоваться, если он доступен, и в противном случае будет использоваться конструктор копирования.

Точное поведение определяется [class.copy]/32:

Когда критерии элизии операции копирования будут выполнены или будут выполнены за исключением того, что исходный объект является параметром функции, и объект скопировать, обозначается lvalue, разрешение перегрузки для выбора конструктора для копии сначала выполняется так, как если бы объект был обозначен rvalue. Если сбой разрешения перегрузки или тип первого параметра выбранного конструктора не является ссылкой rvalue на тип объекта (возможно, cv-qualified), разрешение перегрузки выполняется снова, считая объект как lvalue.

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