为什么没有调用复制构造函数?

cpx*_*cpx 19 c++ copy-constructor

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.
}
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,当MyClass(1, 2)调用用户定义的构造函数并返回一个对象时,我希望MyObj调用复制构造函数.为什么它不需要为第二个实例调用复制构造函数MyClass

AnT*_*AnT 38

每当创建临时对象的唯一目的是被复制并随后销毁时,允许编译器完全删除临时对象并直接在接收者中构造结果(即直接在应该接收副本的对象中).在你的情况下

MyClass MyObj(MyClass(1, 2));
Run Code Online (Sandbox Code Playgroud)

可以转化为

MyClass MyObj(1, 2);
Run Code Online (Sandbox Code Playgroud)

即使拷贝构造函数有副作用.

此过程称为复制操作的省略.它在12.8/15中以语言标准描述.


Pot*_*ter 19

在这种情况下可以省略复制构造函数.

同样地MyClass MyObj = MyClass( 1, 2 );.

std::string str = "hello";
Run Code Online (Sandbox Code Playgroud)

这样的代码有一个隐式的构造函数调用来转换char*为a std::string.

std::string str = std::string( "hello" ); // same, written more verbosely
Run Code Online (Sandbox Code Playgroud)

如果没有copy elision,通过赋值语法进行"简单"字符串初始化会产生额外的深层复制.而且这种语法与你拥有的语法相当于99%.


dir*_*tly 5

除了Potatoswatter和Andrey T.所说的那样,请注意你可以哄骗大多数编译器而不是删除构造函数.GCC通常会为您提供-fno-elide-constructorsMSVC,/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.
}
Run Code Online (Sandbox Code Playgroud)

在MingW32上使用GCC 4.5.0编译:

 g++ -Wall -pedantic -ansi -pedantic tmp.cpp -o tmp -fno-elide-constructors
Run Code Online (Sandbox Code Playgroud)

输出:

$ tmp.exe
MyClass::MyClass(int, int)
MyClass::MyClass(const MyClass&)
MyClass::~MyClass()
MyClass::MyClass(const MyClass&)
MyClass::~MyClass()
MyClass::~MyClass()
Run Code Online (Sandbox Code Playgroud)