Почему конструктор копирования не вызывается?
class MyClass
{
public:
~MyClass() {}
MyClass():x(0), y(0){} //default constructor
MyClass(int X, int Y):x(X), y(Y){} //user-defined constructor
MyClass(const MyClass& tempObj):x(tempObj.x), y(tempObj.y){} //copy constructor
private:
int x; int y;
};
int main()
{
MyClass MyObj(MyClass(1, 2)); //user-defined constructor was called.
MyClass MyObj2(MyObj); //copy constructor was called.
}
В первом случае, когда MyClass(1, 2)
вызывает определяемый пользователем конструктор и возвращает объект, я ожидал, что MyObj
вызовет конструктор копирования. Почему ему не нужно вызывать конструктор копирования для второго экземпляра MyClass
?
Ответы
Ответ 1
Всякий раз, когда временный объект создается с единственной целью копирования и последующего уничтожения, компилятору разрешается полностью удалить временный объект и построить результат непосредственно у получателя (т.е. непосредственно в объекте, который должен получать копия). В вашем случае
MyClass MyObj(MyClass(1, 2));
можно преобразовать в
MyClass MyObj(1, 2);
даже если конструктор копирования имеет побочные эффекты.
Этот процесс называется разрешением операции копирования. Он описан в 12.8/15 в стандарте языка.
Ответ 2
Конструктор копирования может быть отклонен в таком случае.
Аналогично с MyClass MyObj = MyClass( 1, 2 );
.
И с
std::string str = "hello";
Такой код имеет неявный вызов конструктора для преобразования char*
в std::string
.
std::string str = std::string( "hello" ); // same, written more verbosely
Без копирования elision, инициализация "простой" строки по синтаксису присваивания будет иметь дополнительную глубокую копию. И этот синтаксис на 99% эквивалентен тому, что у вас есть.
Ответ 3
Помимо того, что сказал Potatoswatter и Андрей Т., обратите внимание, что вы можете уговорить большинство компиляторов не элиминировать конструкторов. GCC обычно предоставляет вам -fno-elide-constructors
и MSVC с /Od
, которые должны дать вам желаемый результат. Вот код:
#include <iostream>
#define LOG() std::cout << __PRETTY_FUNCTION__ << std::endl // change to __FUNCSIG__ on MSVC > 2003
class MyClass
{
public:
~MyClass() { LOG(); }
MyClass():x(0), y(0){LOG(); } //default constructor
MyClass(int X, int Y):x(X), y(Y){LOG(); } //user-defined constructor
MyClass(const MyClass& tempObj):x(tempObj.x), y(tempObj.y){LOG(); } //copy constructor
private:
int x; int y;
};
int main()
{
MyClass MyObj(MyClass(1, 2)); //User-defined constructor was called.
MyClass MyObj2(MyObj); //Copy constructor was called.
}
Скомпилирован с GCC 4.5.0 на MingW32:
g++ -Wall -pedantic -ansi -pedantic tmp.cpp -o tmp -fno-elide-constructors
Вывод:
$ tmp.exe
MyClass::MyClass(int, int)
MyClass::MyClass(const MyClass&)
MyClass::~MyClass()
MyClass::MyClass(const MyClass&)
MyClass::~MyClass()
MyClass::~MyClass()
Ответ 4
Что заставляет вас думать, что это не вызвано? Попробуйте [Изменить: изменение кода для использования частной копии ctor, так как доступность должна быть проверена, даже если использование копии ctor завершено]:
class MyClass
{
public:
~MyClass() {}
MyClass():x(0), y(0){} //default constructor
MyClass(int X, int Y):x(X), y(Y){} //user-defined constructor
private:
MyClass(const MyClass& tempObj):x(tempObj.x), y(tempObj.y){} //copy constructor
int x; int y;
};
int main()
{
MyClass MyObj(MyClass(1, 2)); //User-defined constructor was called.
MyClass MyObj2(MyObj); //Copy constructor was called.
}
Попытка скомпилировать это дает ошибки для обеих строк в main
:
myclass.cpp(17) : error C2248: 'MyClass::MyClass' : cannot access private member
declared in class 'MyClass'
myclass.cpp(11) : see declaration of 'MyClass::MyClass'
myclass.cpp(4) : see declaration of 'MyClass'
myclass.cpp(18) : error C2248: 'MyClass::MyClass' : cannot access private member
declared in class 'MyClass'
myclass.cpp(11) : see declaration of 'MyClass::MyClass'
myclass.cpp(4) : see declaration of 'MyClass'
Концептуально, копия ctor используется в обоих случаях, и компилятор обязан проверить, что он доступен. В первом случае, однако, компилятор свободен от фактического использования копии ctor, если только он сможет ее использовать.