Возврат локального объекта примитивного типа и структуры
Получение ссылки на временную переменную:
struct S
{
S() = default;
S(const S& other) = delete;
S(S&& other) = delete;
~S(){}
};
S foo1()
{
return {}; // RVO (???)
}
int foo2()
{
return 42; // RVO
}
int main()
{
S& i = foo1(); // compiles!
int& i2 = foo3(); // error C2440: 'initializing' : cannot convert from 'int' to 'int &'
}
Я знаю о продлении срока службы с const
спецификатор. И понятно почему foo2
выдает ошибку. Но почему foo1
работает?
PS: протестировано с VS2013/15
2 ответа
Компиляция со всеми включенными предупреждениями (/Wall
), вы случайно получаете следующее:
source_file.cpp (22): предупреждение C4239: использовано нестандартное расширение: "инициализация": преобразование из "S" в "S &"
gcc 4.9.3 std= C++14 не нравится ни одна из инициализаций.
Если мы изменим foo1()
в
S foo1()
{
S s;
return s;
}
Также жалуется на удаленный ход ctor. Я не уверен, почему оригинальный код не нужен.
Cppreference гласит: "Даже когда удаление копии происходит, а конструктор копирования / перемещения не вызывается, он должен присутствовать и быть доступным (как если бы оптимизация вообще не происходила), в противном случае программа плохо сформирована".
В стандарте 12,8 / 32:
[Примечание: это двухэтапное разрешение перегрузки должно выполняться независимо от того, будет ли выполнено копирование. Он определяет конструктор, который будет вызван, если elision не выполняется, и выбранный конструктор должен быть доступен, даже если вызов исключен. —Конечная записка]
Я понимаю, что это примечание относится к поиску правильного конструктора перемещения (первая попытка) или копирования (вторая попытка), а не другого.