我为类更改了默认构造函数,但似乎编译器仍在调用默认构造函数

时间:2019-05-05 17:42:14

标签: c++ constructor

我创建一个类A,并覆盖operator +和构造函数A(A&&),我想知道是否调用

A a, b;
A c = a + b;

我的构造函数A(A &&)被调用了吗?

我尝试了一些代码,但结果却很混乱

//try2.cpp

#include <iostream>
#include <string>
using namespace std;
class A {
public:
  string s;
  A(A &&a) { s=std::move(a.s); cout<<"A(A &&a) called"<<endl;}
  A() {}
};

A operator+(const A &a, const A &b) {
  A c;
  c.s=a.s+b.s;
  return c;
}

int main() {
  A a,b;
  a.s = "123";
  b.s = "456";
  A c = a+b;
  cout<<c.s<<endl;
  return 0;
}

我使用了gcc 7.0:g++ -std=c++1y try2.cpp

输出为123456,因此未调用A(A &&a)

但是后来我改变了

A(A &&a) = delete;

然后编译器抛出错误:

try2.cpp: In function ‘A operator+(const A&, const A&)’:
try2.cpp:14:10: error: use of deleted function ‘A::A(A&&)’
   return c;
          ^
try2.cpp:7:3: note: declared here
   A(A &&a) = delete;
   ^
try2.cpp: In function ‘int main()’:
try2.cpp:21:11: error: use of deleted function ‘A::A(A&&)’
   A c = a+b;
           ^
try2.cpp:7:3: note: declared here
   A(A &&a) = delete;

构造函数A(A &&a)是必需的。但是为什么以前的代码没有调用它?

2 个答案:

答案 0 :(得分:1)

Named Return Value Optimization

编译器意识到,与其(在A范围内创建operator+并将其从operator+移到main中,它可以(基本上)只是在main中构造它,并使operator+main中的值上工作。

为了使您的程序有效,您需要一些构造函数来复制该值-但如果编译器意识到可以优化某些副本/移动,则无需使用它。

答案 1 :(得分:1)

这里发生的是copy elision。您的move构造函数没有被调用,因为编译器可以选择构造您的对象'c',该对象正在您的operator +函数内部使用,直接指向调用站点上的对象'c'。这是一个可选的优化,它避免了额外的移动(或复制)构造函数。

显式删除move构造函数时会遇到编译错误,因为这是编译器的可选优化。如果需要,仍然允许编译器调用复制/移动构造函数,但是通过显式删除move构造函数,您也将隐式删除复制构造函数。这不会为编译器留下非复制省略选项,因此会导致错误。