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
的第二个实例调用复制构造函数?
答案 0 :(得分:38)
每当创建临时对象的唯一目的是复制并随后销毁时,允许编译器完全删除临时对象并直接在接收者中构造结果(即直接在应该接收的对象中)复制)。在你的情况下
MyClass MyObj(MyClass(1, 2));
可以转化为
MyClass MyObj(1, 2);
即使复制构造函数有副作用。
此过程称为复制操作的省略。它在12.8 / 15中以语言标准描述。
答案 1 :(得分:19)
这种情况下的复制构造函数may be elided。
与MyClass MyObj = MyClass( 1, 2 );
相同。
并且
std::string str = "hello";
此类代码具有隐式构造函数调用,可将char*
转换为std::string
。
std::string str = std::string( "hello" ); // same, written more verbosely
如果没有copy elision,通过赋值语法进行“简单”字符串初始化会产生额外的深层复制。而且这种语法与你拥有的语法相当于99%。
答案 2 :(得分:5)
除了Potatoswatter和Andrey T.所说的内容之外,请注意你可以哄骗大多数编译器而不是删除构造函数。 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.
}
在MingW32上用GCC 4.5.0编译:
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()
答案 3 :(得分:2)
是什么让你认为不是被调用?试试这个[编辑:更改代码以使用私人复制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的实际使用,只要 能够使用它。