为什么我需要类型 T 的复制构造函数?

Why do I need a copy constructor for type T?

我有点不确定什么时候需要复制构造函数。例如,给出这个函数:

template<class T>
T max(const T* array, int size) {
    T result = array[0];
    for (int i = 1; i < size; ++i) {
        if (result < array[i]) {
            result = array[i];
        }
    }
    return result;
}

我需要类型 T 的复制构造函数的原因是什么?我认为这一定是因为我们 return 按价值计算。这行T result = array[0];是否也需要复制构造函数?

What is the reason that I need copy constructor for the type T?

T result = array[0];

这称为复制初始化并调用类型 T 的复制构造函数。键入 T 需要 一个复制构造函数才能使此行成功。

I think that it's must be because that we return by a value, and so we need copy constructor for T type.

return result;

在大多数情况下,您的假设对于 return 值是正确的。但是,在这种情况下没有必要定义复制构造函数。要实现 move semantics,您可以实现移动构造函数,这将消除对复制构造函数的需要,因为局部变量 result 将是 "moved" 而不是 "copied"。当从函数 returning 大对象时,移动语义消除了对大对象不必要副本的需要,因为在函数 return 之后将无法访问这些大对象。

这里已经回答了:

What's the difference between assignment operator and copy constructor?

所以事情是:

复制构造函数用于从其他对象的数据初始化以前未初始化的对象。

赋值运算符用于用其他对象的数据替换先前初始化的对象的数据。

这是一个例子:

#include <iostream>

using namespace std;


class MyClass{
public:
  MyClass(){
    cout << "Default ctor\n";
  }

  MyClass(const MyClass& copyArg){
    cout << "Copy ctor\n";
  }

  MyClass(MyClass&& moveArg){
    cout << "Move ctor\n";
  }

  void operator=(const MyClass& assignArg){
    cout << "Assignment operator\n";
  }

  bool operator<(const MyClass& comparsionArg) const {
    return true;
  }
};

template<class T>
T max(const T* array, int size) {
    T result = array[0];
    for (int i = 0; i < size; ++i) {
        if (result < array[i]) {
            result = array[i];
        }
    }
    return result;
}


int main(){

  MyClass arr[1];

  const MyClass& a = max(arr, 1);

  return 0;
}

查看到底发生了什么we need to compile with -fno-elide-constructors

输出为:

Default ctor
Copy ctor
Assignment operator
Move ctor

所以在这里,默认构造函数在这一行为数组的一个元素调用:

MyClass arr[1];

然后我们初始化一个之前未初始化的对象并且复制构造函数被调用:

T result = array[0];

然后我们对先前初始化的对象和赋值运算符进行赋值:

result = array[i];

在我们需要在函数范围之外创建对象之后,因为我们 return 按值并为此 移动构造函数 调用:

return result;

然后将 main 范围内移动构造函数 构造的对象绑定到 const 引用:

const MyClass& a = max(arr, 1);