构造函数被调用的次数

时间:2019-01-10 00:26:56

标签: c++ class constructor copy-constructor

假设我们有一个自定义字符串类,如下所示

using namespace std;

class CustomStr {
public:
  const char* s;

  // converting constructor
  CustomStr(const char* s) : s (s) {
    cout << "Constructor called" << endl;
  }

  // Copy constructor    
  CustomStr(const CustomStr& cs) : s (cs.s) {
    cout << "Copy Constructor called" << endl;
  }
};

让我们考虑以下代码:

int main() {
  CustomStr cs("Some char pointer");
  CustomStr cs_copy = cs;
  return 0;
}

在上述情况下,我们期望CustomStr cs_copy = cs首先调用转换构造函数,然后再调用复制构造函数,并按预期获得相应的输出

$ ./a.out
Constructor called
Copy Constructor called

现在,考虑以下代码

int main() {
  CustomStr cs_copy = CustomStr("Some char pointer");
  return 0;
}

在这种情况下,我也认为应该进行2个构造函数调用-转换CustomStr("Some char pointer")的构造函数调用和复制CustomStr cs_copy = CustomStr("Some char pointer")的构造函数调用。但是,输出仅显示正在转换的构造函数。

我无法解释这是怎么发生的。我希望它对编译器进行优化是一项艰巨的任务-但我想了解在什么情况下可以进行此优化。

2 个答案:

答案 0 :(得分:3)

引用cppreference

  

如果初始值设定项是类型与T相同的prvalue表达式(忽略cv限定),则将初始值设定项表达式本身(而不是从其实例化的初始值)用于初始化目标对象

CustomStr("Some char pointer")是与cs_copy类型相同的prvalue。因此,没有临时的副本。 cs_copy可以直接从该表达式直接初始化。

在C ++ 17之前,就抽象机而言曾经是一个临时的,但是该标准不需要调用复制构造函数,因此与C ++ 17相同的行为被允许作为优化。有关更多详细信息,请参见cppreference:copy elision

答案 1 :(得分:2)

自C ++ 17起,T x = T(A);的定义与以下内容完全相同:T x(A);。 (其中A是任何表达式列表,可能是空的,并且没有MVP)。

在C ++ 17之前,编译器可以选择是否将代码作为T x(A);处理,还是选择构造一个临时文件,然后从该临时文件中复制/移动构造文件x