Для этой программы
#include <iostream>
using std::cout;
struct C
{
C() { cout << "Default C called!\n"; }
C(const C &rhs) { cout << "CC called!\n"; }
};
const C f()
{
cout << "Entered f()!\n";
return C();
}
int main()
{
C a = f();
C b = a;
return 0;
}
вывод, который я получаю:
Entered f()!
Default C called!
CC called!
С тех пор f()
возвращается значением, оно должно возвратить временный файл. Как T a = x;
T a(x);
, не был бы он вызывать конструктора копии для конструкции a
, с временным файлом передал - в как его аргумент?
Поскольку
f ()
возвращается по значению, он должен возвращать временное значение. ПосколькуT a = x;
isT a (x);
, не будет ли он вызывать конструктор копирования для построенияa
с временным переданным -in в качестве аргумента?
Найдите оптимизацию возвращаемого значения. По умолчанию это включено. Если вы работаете в Windows и используете MSVC 2005+, вы можете использовать / Od
, чтобы отключить это и получить желаемый результат (или -fno-elide-constructors
в GCC). Также для MSVC см. эту статью.
12.8 Копирование объектов класса
15 При соблюдении определенных критериев реализации разрешается опускать конструкцию копирования объекта класса, даже если конструктор копирования и / или деструктор для объекта имеют побочные эффекты .В таких случаях реализация рассматривает источник и цель пропущенной операции копирования как просто два разных способа ссылки на один и тот же объект, а уничтожение этого объекта происходит в более позднем из моментов, когда два объекта были бы уничтожены без оптимизации {{1} }.115 Это Исключение операций копирования разрешено в следующих обстоятельствах (которые могут быть объединены для удаления нескольких копий):
- в оператор return в функции с типом возврата класса, , когда выражение является именем энергонезависимого автоматического объекта с таким же cv-unqualified в качестве типа возвращаемого значения функции , операцию копирования можно опустить, создав автоматический объект непосредственно в возвращаемом функцией функции {{1} } value - в выражении throw, когда операнд является именем энергонезависимого автоматического объекта , операция копирования fr операнд объекта исключения (15.1) может быть опущен путем создания автоматического объекта непосредственно в объекте исключения
- , когда временный объект класса, который не был привязан к ссылке (12.2) , будет скопирован в объект класса с тем же типом cv-unqualified, копия операция может быть опущена путем создания временного объекта непосредственно в целевом объекте пропущенной копии
- когда объявление исключения для исключения { Обработчик {1}} (пункт 15) объявляет объект того же типа (за исключением cv-qualification) как объект исключения (15.1), операцию копирования можно опустить, рассматривая объявление-исключения как псевдоним для объекта исключения, если значение программы будет без изменений, за исключением для выполнения конструкторов и деструкторов для объекта, объявленного объявлением исключения.
Примечание: Акцент мой
Я полагаю, это называется оптимизация возвращаемого значения.
Я предполагаю, что когда f()
возвращает C
объект, объект выделяется в стековом пространстве вызывающего метода, поэтому не требуется копирование для инициализации C a
. Это ваш вызываемый по умолчанию C
.
C b = a
Это вызывает конструктор копирования, следовательно, ваш CC называется
.
Кстати, пример на вики выглядит очень похожим на ваш код.
Это пример оптимизации возвращаемого значения (RVO) функции, которые поддерживает ваш компилятор.
Конструктор копирования может не вызываться при возврате по значению.
Используйте параметр -fno-elide-constructors
в GCC, чтобы отключить эту функцию.