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