2013-07-05 4 views
17

В comment to another question Джонатан Wakely отвечает на мое заявление:Когда требуется явное перемещение для оператора возврата?

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

->

... никогда не говори никогда ... Вам нужен явный шаг, если локальная переменная не тот же тип, тип возвращаемого значения, например, 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; 
} 

хороша тем, что она дает compilation error

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

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

ответ

18

Update:

Явное движение не должно быть необходимости в современных версиях компилятора.

Core DR 1579 изменил правила так, чтобы возвращаемое значение считалось значением r, даже если типы не совпадают. 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 говорит:

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

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

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

+3

Я первоначально отправил это предложение Майку и Ричарду на рассмотрение в Бристоль, но, похоже, они не добрались до него. :( – Xeo

+1

Давайте нажимаем, чтобы получить его на C++ 17. Я не уверен, как изменить формулировку, хотя - текущее правило имеет преимущество простоты. –

+0

Я думаю, мы пришли к выводу, что правило должно быть отделено от правила копирования-исключения и просто указать «если возвращаемое выражение является именем автоматической локальной переменной или функциональным параметром, переместите ее». – Xeo