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,

Кстати, пример на вики выглядит очень похоже на ваш код.

Другие вопросы по тегам