Когда необходимо явное перемещение для оператора возврата?

В комментарии к другому вопросу Джонатан Уэйкли отвечает на мое заявление:

Вам никогда не нужно явно перемещать возвращаемое значение функции локальной переменной. Это неявное движение туда

->

... никогда не говори никогда... Вам нужно явное перемещение, если локальная переменная не совпадает с типом возвращаемого значения, например std::unique_ptr<base> f() { auto p = std::make_unique<derived>(); p->foo(); return p; }, но если типы одинаковы, он будет двигаться, если это возможно...

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

Пример

std::unique_ptr<base> f() { 
  auto p = std::make_unique<derived>();
  p->foo(); 
  return p; 
}

приятно в том, что это дает ошибку компиляции

> prog.cpp:10:14: error: cannot convert ‘p’ from type
> ‘std::unique_ptr<derived>’ to type ‘std::unique_ptr<derived>&&’

но мне интересно, есть ли хороший шанс обнаружить это вообще - и здесь ли это ограничение языковых правил илиunique_ptr??

1 ответ

Решение

Обновить:

Явное перемещение не требуется в современных версиях компилятора.

Core DR 1579 изменил правила, так что возвращаемое значение будет рассматриваться как значение, даже если типы не совпадают. GCC 5 реализует новое правило для C++11 и C++14.

Оригинальный ответ:

Это не ограничение unique_ptr, это ограничение языка, такое же ограничение применяется к любому return оператор, который вызывает конвертирующий конструктор со ссылкой на rvalue:

struct U { };

struct T {
  T(U&&) { }
};

T f() {
  U u;
  return u;  // error, cannot bind lvalue to U&&
}

Это не скомпилируется, потому что [class.copy]/32 говорит:

Когда критерии для исключения операции копирования выполнены или будут выполнены, за исключением того факта, что исходный объект является параметром функции, а копируемый объект обозначен lvalue, разрешением перегрузки для выбора конструктора для копирования является сначала выполняется, как если бы объект был обозначен как rvalue.

Это означает, что выражение в return Оператор может рассматриваться как значение r, только если он имеет право на исключение копирования / перемещения (или NRVO), но это слишком ограничительно, поскольку означает, что он применяется только тогда, когда тип точно такой же, даже если переменная всегда выходит из области видимости. так что было бы разумно всегда рассматривать это как rvalue (технически как xvalue, значение с истекающим сроком действия.)

Это было недавно предложено Richard Smith (и ранее Xeo), и я думаю, что это очень хорошая идея.

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