C++ Copy конструктор, временные и копировальные семантики
Для этой программы
#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
с временной передачей в качестве аргумента?
3 ответа
поскольку
f()
возвращается по значению, он должен вернуть временный. КакT a = x;
являетсяT a(x);
не будет ли вызывать конструктор копирования для построенияa
с временной передачей в качестве аргумента?
Посмотрите Оптимизацию возвращаемого значения. Это включено по умолчанию. Если вы используете Windows, используя MSVC 2005+, вы можете использовать /Od
чтобы отключить это и получить желаемый результат (или -fno-elide-constructors
на GCC). Также для MSVC смотрите эту статью.
12.8 Копирование объектов класса
15 При соблюдении определенных критериев реализация может опустить конструкцию копирования объекта класса, даже если конструктор копирования и / или деструктор для объекта имеют побочные эффекты. В таких случаях реализация рассматривает источник и цель пропущенной операции копирования как просто два разных способа обращения к одному и тому же объекту, и уничтожение этого объекта происходит в более поздние времена, когда два объекта были бы уничтожены без Оптимизация.115 Это исключение операций копирования допускается при следующих обстоятельствах (которые могут быть объединены для устранения нескольких копий):
- в операторе return в функции с типом возврата класса, когда выражение является именем энергонезависимого автоматического объекта с тем же типом cv-unqualified, что и тип возврата функции, операция копирования может быть опущена путем создания автоматического Объект непосредственно в возвращаемое значение функции - в выражении throw, когда операндом является имя энергонезависимого автоматического объекта, операция копирования из операнда в объект исключения (15.1) может быть опущена путем непосредственного конструирования автоматического объекта. в объект исключения
- когда временный объект класса, который не был связан со ссылкой (12.2), будет скопирован в объект класса с тем же типом cv-unqualified, операция копирования может быть опущена путем создания временного объекта непосредственно в цель опущенного копия
- когда объявление исключения в обработчике исключений (пункт 15) объявляет объект того же типа (за исключением cv-квалификации), что и объект исключения (15.1), операция копирования может быть опущена путем обработки объявления исключения как псевдоним для объекта исключения, если значение программы не изменится, за исключением выполнения конструкторов и деструкторов для объекта, объявленного объявлением исключения.
Примечание: акцент мой
Это пример функций оптимизации возвращаемых значений (RVO), которые поддерживает ваш компилятор.
Конструктор копирования может не вызываться при возврате по значению.
использование -fno-elide-constructors
опция в GCC, чтобы отключить эту функцию.
Я считаю, что это называется оптимизацией возвращаемого значения.
Я предполагаю когда f()
возвращается C
объект объект размещен в пространстве стека вызывающего метода, поэтому для инициализации не требуется никакой копии C a
, Это ваша default C called
,
C b = a
Это вызывает конструктор копирования, следовательно, ваш CC called
,
Кстати, пример на вики выглядит очень похоже на ваш код.