Скопировать конструктор elision?
Возможный дубликат:
Почему деструктор был вызван только один раз?
Учитывая код ниже, я не понимаю вывод в gcc. Я ожидаю, что два объекта будут созданы и уничтожены, но вместо этого я вижу только один вызов конструктора и деструктора. Что тут происходит?
#include <string>
#include <iostream>
struct Huge{
Huge() { std::cout << "Constructor" << std::endl; }
Huge(Huge const &r) { std::cout << "Copy Constructor" << std::endl; }
~Huge() { std::cout << "Destructor" << std::endl; }
};
Huge g() {
std::cout << "Entering g" << std::endl;
Huge temp;
std::cout << "Exiting g" << std::endl;
return temp;
}
int main(){
Huge h2(g());
std::cout << "Before leaving main" << std::endl;
}
Вывод этого кода в g++ (4.4)
Ввод г
Конструктор
Выход г
Перед выходом из основного
Destructor
2 ответа
Да, это копирование с помощью оптимизации именованных возвращаемых значений.
Стандарт C++ позволяет реализации опустить операцию копирования, являющуюся результатом оператора return, даже если конструктор копирования имеет побочные эффекты.
Ссылка:
Стандарт C++03:
12.8 Копирование объектов класса:
№ 15
Когда определенные критерии выполнены, реализация может опустить конструкцию копирования объекта класса, даже если конструктор копирования и / или деструктор для объекта имеют побочные эффекты. В таких случаях реализация рассматривает источник и цель пропущенной операции копирования как просто два разных способа обращения к одному и тому же объекту, и уничтожение этого объекта происходит в более поздние времена, когда два объекта были бы уничтожены без Оптимизация.111) Это исключение операций копирования допускается при следующих обстоятельствах (которые могут быть объединены для устранения нескольких копий):
- в операторе return в функции с типом возврата класса, когда выражение является именем энергонезависимого автоматического объекта с тем же типом cv-unqualified, что и тип возврата функции, операция копирования может быть опущена путем создания автоматического объект непосредственно в возвращаемое значение функции
- когда временный объект класса, который не был связан со ссылкой (12.2), будет скопирован в объект класса с тем же типом cv-unqualified, операция копирования может быть опущена путем создания временного объекта непосредственно в цель опущенного копия
C++ позволяет избежать создания и копирования дополнительных объектов в таких случаях, как ваш. Это известно как названная оптимизация возвращаемого значения. Дело в том, что вы точно знаете, что после возврата объекта temp
в любом случае исчезнет, и семантика конструктора копирования должна состоять в том, чтобы сделать точно эквивалентную копию оригинальному объекту.
Обратите внимание, что на самом деле здесь происходят две оптимизации. Без оптимизации, объект temp
будет сначала скопирован в возвращаемое значение в g
, а затем возвращаемое значение будет скопировано в h2
в main
, Оптимизация именованного возвращаемого значения исключает копию в возвращаемое значение. Копирование из возвращаемого значения в h2
исключается, потому что возвращаемое значение является временным объектом, и в этом случае создание копии также может быть исключено.
Обратите внимание, что в отличие от других оптимизаций, эти оптимизации разрешены, даже если они изменяют наблюдаемое поведение (как в вашей тестовой программе). Это потому, что в противном случае эта оптимизация не может быть выполнена во многих случаях, когда она не имеет значения (действительно, за исключением отладки вывода, это никогда не должно иметь значения в хорошо написанной программе), потому что компилятор часто не может доказать, что elision не изменит наблюдаемого поведения. С другой стороны, невозможно вручную удалить копии, поэтому важно, чтобы компилятор мог сделать это автоматически.
В конечном итоге происходит то, что объект temp
напрямую создается в космосе h2
занимает, так что в точке возврата оператора h2
уже содержит правильное значение. Другими словами, из-за оптимизации temp
а также h2
на самом деле один и тот же объект.