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

发布于 2024-09-18 07:52:42 字数 576 浏览 6 评论 0原文

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 的第二个实例调用复制构造函数?

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.
}

In the first case, when MyClass(1, 2) calls the user-defined constructor and returns an object, I was expecting MyObj to call the copy constructor. Why it doesn't need to call the copy constructor for the second instance of MyClass?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

月亮坠入山谷 2024-09-25 07:52:42

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

MyClass MyObj(MyClass(1, 2));

可以转化为

MyClass MyObj(1, 2);

即使复制构造函数有副作用,也

。这个过程称为复制操作的省略。它在语言标准12.8/15中有描述。

Whenever a temporary object is created for the sole purpose of being copied and subsequently destroyed, the compiler is allowed to remove the temporary object entirely and construct the result directly in the recipient (i.e. directly in the object that is supposed to receive the copy). In your case

MyClass MyObj(MyClass(1, 2));

can be transformed into

MyClass MyObj(1, 2);

even if the copy constructor has side-effects.

This process is called elision of copy operation. It is described in 12.8/15 in the language standard.

人间不值得 2024-09-25 07:52:42

在这种情况下,复制构造函数可能会被省略

MyClass MyObj = MyClass( 1, 2 ); 类似。

这样

std::string str = "hello";

的代码有一个隐式构造函数调用,将 char* 转换为 std::string

std::string str = std::string( "hello" ); // same, written more verbosely

如果没有复制省略,通过赋值语法进行的“简单”字符串初始化将产生额外的深层复制。该语法与您所拥有的语法 99% 等效。

The copy constructor may be elided in such a case.

Likewise with MyClass MyObj = MyClass( 1, 2 );.

And with

std::string str = "hello";

Such code has an implicit constructor call to convert the char* to a std::string.

std::string str = std::string( "hello" ); // same, written more verbosely

Without copy elision, the "easy" string initialization by assignment syntax would incur an additional deep copy. And that syntax is 99% equivalent to what you have.

梦晓ヶ微光ヅ倾城 2024-09-25 07:52:42

除了 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()

Apart from what Potatoswatter and Andrey T. has said, note that you can coax most compilers not to elide constructors. GCC typically provides you with -fno-elide-constructors and MSVC with /Od which should give you the desired output. Here's some code:

#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.
}

Compiled with GCC 4.5.0 on MingW32:

 g++ -Wall -pedantic -ansi -pedantic tmp.cpp -o tmp -fno-elide-constructors

Output:

$ tmp.exe
MyClass::MyClass(int, int)
MyClass::MyClass(const MyClass&)
MyClass::~MyClass()
MyClass::MyClass(const MyClass&)
MyClass::~MyClass()
MyClass::~MyClass()
一张白纸 2024-09-25 07:52:42

是什么让您认为它没有被调用?试试这个[编辑:更改代码以使用私有复制构造函数,因为即使使用复制构造函数被省略,也必须检查可用性]:

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 中的 em> 行:

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'

从概念上讲,在这两种情况下都使用复制构造函数,并且编译器有义务检查它是否可访问。然而,在第一种情况下,编译器可以自由地忽略复制构造函数的实际使用,只要它能够使用它。

What makes you think it's not invoked? Try this [Edit: changing code to use private copy ctor, since availability has to be checked even if use of the copy ctor is elided]:

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.
}

Attempting to compile this gives errors for both lines in 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'

Conceptually, the copy ctor is used in both cases, and the compiler is obliged to check that it's accessible. In the first case, however, the compiler is free to elide actual use of the copy ctor, as long as it would be able to use it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文