Ответ 1
Конструктор копирования не может быть вызван при возврате по значению. Некоторые компиляторы используют функцию оптимизации возвращаемых значений.
Подробнее о Оптимизация возвращаемого значения "
Насколько я знаю, конструктор копирования вызывается в следующих сценариях:
1) Pass by value
2) Return by value
3) When you create and initialize a new object with an existing object
Здесь программа:
#include <iostream>
using namespace std;
class Example
{
public:
Example()
{
cout << "Default constructor called.\n";
}
Example(const Example &ob1)
{
cout << "Copy constructor called.\n";
}
Example& operator=(const Example &ob1)
{
cout << "Assignment operator called.\n";
return *this;
}
~Example()
{
cout<<"\nDtor invoked"<<endl;
}
int aa;
};
Example funct()
{
Example ob2;
ob2.aa=100;
return ob2;
}
int main()
{
Example x;
cout << "Calling funct..\n";
x = funct();
return 0;
}
Вывод:
Вызывается конструктор по умолчанию.
Функция вызова.
Вызывается конструктор по умолчанию.
Вызывается оператор присваивания.
Dtor вызывается
Dtor вызывается
Пожалуйста, исправьте меня, IIRC должна произойти следующая последовательность вызовов:
1) Конструктор x называется
2) Конструктор ob2 называется
3) Функция возвращается и поэтому вызывается конструктор копирования (чтобы скопировать ob2 в неназванную временную переменную i.e funct())
4) Деструктор ob2, называемый
5) Назначьте неназванную временную переменную x
6) Уничтожьте временную переменную i.e вызовите ее деструктор
7) Уничтожьте x i.e вызовите x destructor
Но тогда почему конструктор копирования не вызывается, и также есть только 2 обращения к dtors, тогда как я ожидаю 3.
Я знаю, что компилятор может делать оптимизации, однако, правильно ли я понимаю?
Большое спасибо:)
Привет
Lali
Конструктор копирования не может быть вызван при возврате по значению. Некоторые компиляторы используют функцию оптимизации возвращаемых значений.
Подробнее о Оптимизация возвращаемого значения "
Часть стандарта, которая сообщает вам, когда компиляторы могут выдавать копии, составляет 12.8/15. Всегда нужно компилятору, действительно ли выполнять эликсирование. Есть две юридические ситуации, плюс любая их комбинация:
"в возвращаемом выражении в функции с типом возвращаемого класса, когда выражение является именем энергонезависимого автоматического объекта с тем же самым cv-неквалифицированным типом, что и тип возвращаемого значения функции
", когда временный объект класса, который не был привязан к ссылке, будет скопирован в объект класса с тем же самым cv-неквалифицированным типом".
Первый обычно называется "Именованная оптимизация значений", и это то, что разрешает вывод, который вы видите в своем примере. Последнее по сути превращает инициализацию копирования в прямую инициализацию и может происходить, например, если ваш код сделал Example x = Example();
.
Другие копии исключений не допускаются, за исключением того, что применяются обычные правила "как есть". Поэтому, если конструктор копирования имеет трассировку, тогда следующий код должен вызвать его:
Example x;
Example y = x;
Но если x в противном случае не использовался, и у cctor не было побочных эффектов, тогда я думаю, что его можно было бы оптимизировать, как и любой другой код, который ничего не делает.
При выполнении x = funct(); компилятор замечает, что он будет возвращен непосредственно и, таким образом, позволит избежать бесполезной конструкции. Вот почему вы получите только два вызова деструктора.
Вот пример, почему иногда работа с "копией" не обязательно является потерянной.
В вашем примере структура достаточно мала, поэтому она проходит через регистр. Сгенерированный код похож на Оптимизация возвращаемого значения. Постройте более сложный пример, и вы увидите ожидаемое поведение.
g++ v4.4.1 имеет возможность подавлять оптимизацию "elide":
[email protected]$ g++ -fno-elide-constructors Example.cpp -o Example [email protected]$ ./Example Default constructor called. Calling funct.. Default constructor called. Copy constructor called. Dtor invoked Assignment operator called. Dtor invoked Dtor invoked
Как вы видите, теперь конструктор копирования вызывается!