Рассмотрите следующий код,
struct foo
{
foo()
{
std::cout << "Constructing!" << std::endl;
}
foo(const foo& f)
{
std::cout << "Copy constructing!" << std::endl;
}
~foo()
{
std::cout << "Destructing.." << std::endl;
}
};
foo get()
{
foo f;
return f;
}
int main()
{
const foo& f = get();
std::cout << "before return" << std::endl;
return 0;
}
Вывод на MSVC
Constructing!
Copy constructing!
Destructing..
before return
Destructing..
Вывод GCC
Constructing!
before return
Destructing..
Результат, который прибывает в MSVC, выглядит неправильным.
Вопросы
const foo& f = get()
и const foo f = get()
производит тот же вывод из-за оптимизации возвращаемого значения. В этом случае, какой способ записать должен быть предпочтен?Любые мысли..
В вашей сборке MSVC нет оптимизаций. Включите их, вы получите одинаковый результат для обоих.
GCC по умолчанию просто выполняет RVO на вашем временном сервере. В основном это работает:
const foo& f = foo();
MSVC - нет. Он делает foo
в функции, копирует его за пределы функции (следовательно, вызов конструктора копирования), разрушает внутренний foo
, а затем связывает ссылку.
Оба выхода верны. RVO - это тот случай, когда стандарт явно позволяет изменять наблюдаемое поведение программы.
Вы видите оптимизацию возвращаемого значения , которая является одним из видов исключения копий . Обе программы верны; компилятору специально дается возможность исключить временный объект, который служит только для перемещения данных из одного постоянного объекта в другой.
1) Это происходит из-за разной стратегии оптимизации. Поскольку у вас нет operator=, MSVC может перестроить код в что-то вроде const foo& f(get()), таким образом выполняя copy onstructor. 2) Зависит от того, чего вы хотите добиться:
const foo& f = get();
f = get(); // Incorrect, const references cannot be reassigned.
const foo g = get();
g = get(); // Correct.
Функция get () создает локальный объект (построение печати!) И возвращает объект Foo по значению. Возвращаемый объект Foo должен быть создан с помощью конструкции копирования (конструкция print Copy!). Обратите внимание, что это значение объекта, присвоенное константе foo & f в main.
Однако до того, как это присваивание произойдет, функция должна вернуться из get (), а локальные переменные (т.е. foo f; в get ()) должны быть уничтожены. (выведите 1-е уничтожение ..) Оттуда программа завершается (т.е. возвращается из main), затем объект, возвращенный get () и назначенный для "f", уничтожается. (напечатайте 2nd Destructing ...)
Причина, по которой вы видите разные результаты для двух компиляторов, заключается в том, что GCC оптимизирует возвращаемое значение для get () и просто заменяет const foo & f = get ()
в const foo & f = foo
;