2016-08-13 10 views
34
#include<iostream> 
using namespace std; 

struct B{}; 

struct A 
{ 
    A(const B &) 
    { 
     cout<<"A(const B &)"<<endl; 
    } 
    A(B &&) 
    { 
     cout<<"A(B &&)"<<endl; 
    } 
}; 

A get() 
{ 
    B b; 
    return b; 
} 

int main() 
{ 
    get(); 
} 

Я тестировал код с VC++ 14,2 и GCC 5.4.0, оба из них выход:Почему в этом случае вызывается конструктор ссылок r-value?

A(B &&) 

Почему выход не

A(const B &) 

?

Имеет ли этот код какое-либо отношение к copy elision? (Но A и B - разные типы, поэтому copy elision не должен работать здесь)

+1

Это действительно очень интересный вопрос. Я считаю, что формулировка в 12.8/32 несколько неясна: неясно, должен ли тип возвращаемого выражения быть таким же, как тип возврата функции, чтобы правило применялось. Я думаю, вы могли бы прочитать его, как если бы * любой возвращаемый объект с автоматическим хранилищем считался обозначенным rvalue. Различные компиляторы [думают по-другому об этом] (http://melpon.org/wandbox/permlink/meIAgmvSOVq435vy). –

+0

[CWG1579] (http://wg21.link/cwg1579) кажется актуальным здесь. –

+0

@KerrekSB в соответствии с (31.1), 'когда выражение является именем энергонезависимым автоматическим объектом (кроме параметра функции или переменной, введенной объявлением исключения обработчика (15.3)) с тем же типом (игнорируя cv-qualification) как функцию return type', я думаю, что 'тот же тип' должен быть точно таким же, как' return type'. Это означает, что 'copy elision' будет работать, если я возвращу объект' A'. Но неявное преобразование из 'B' в' A' происходит до того, как 'copy elision',' copy elision' не должно влиять на 'implicit conversion'. – Caesar

ответ

29

Правила возврата как правило были изменены в ответ на обзор перед публикацией C++ 14. Изменения были добавлено в конце процесса, и захватываются CWG Issue 1579, которая вносит изменения в 12,8/32 с формулировкой:

или когда выражение в return утверждения (возможно, в скобках) ID выражения, что имена объект с автоматическим временем хранения, объявленным в теле

Это означает, что возвращение любой локальной переменной теперь рассматривает объект, назначенный этой переменной, как если бы это было сначала значение rval (повторное попытку, если сбой при перегрузке завершился с ошибкой).

Поскольку проблема CWG была принята как дефект в языке, компиляторы могут реализовать это новое правило даже в режиме «C++ 11». Точка дефекта заключается в том, что «это всегда предназначалось для работы таким образом», поэтому это не является строго выражением изменений между C++ 11 и C++ 14, а, скорее, значение C++ 11 было изменено в 2014 году.

+0

Заявление можно найти в n4594 §12.8 32. Я думал, что работает только при выполнении 'copy elision' !!! – Caesar

+0

@Caesar: Да, как это было раньше. Но связанная основная проблема заключалась в том, что «было бы неплохо, если бы она также работала в более общем плане», а затем был комментарий национального органа, чтобы это изменилось, поэтому оно изменилось.Связанная проблема содержит мотивирующий пример, очень похожий на ваш. –

+0

@Caesar Да, я делаю эту ошибку, когда читаю это каждый раз. Это очень сложное предложение. Но подумайте об этом так. Если вы возвращаете автоматическую переменную хранилища по имени, это, безусловно, безопасно перемещаться, поэтому почему бы вам не сделать этот язык автоматически? – Barry

5

Копирование elision связано с A, не будучи построенным в стеке get(). Что происходит, так это то, что возвращенный b (это временный, поскольку «собирается умереть из-за возврата»: это с C++ 14), используется для создания копируемого файла A в главном стеке.

И поскольку временные объекты связывают ссылки r-значения, это то, что вы наблюдали.

+0

Где я могу найти инструкцию в стандарте ISO C++ (прямо сейчас, n4594)? – Caesar

+0

Я читал об этом здесь: http://en.cppreference.com/w/cpp/language/return –

+1

ну, но перед выполнением 'copy elision' происходит неявное преобразование. – Caesar

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

  • Нет связанных вопросов^_^