C++ 初始值设定项列表:复制构造函数和赋值运算符=冗余?

C++ 初始值设定项列表:复制构造函数和赋值运算符=冗余?,c++,copy-constructor,assignment-operator,initialization,C++,Copy Constructor,Assignment Operator,Initialization,似乎initalizer列表是类构造函数的首选项,我假设也是复制构造函数的首选项。对于赋值运算符,必须为函数体中的每个成员赋值。考虑下面的简单块: class Foo { private: int a,b; public: Foo(int c, int d) : a(c), b(d) {} Foo(const Foo & X) : a(X.a), b(X.b) {} Foo& operator=(const Foo& X) { if (this

似乎initalizer列表是类构造函数的首选项,我假设也是复制构造函数的首选项。对于赋值运算符,必须为函数体中的每个成员赋值。考虑下面的简单块:

class Foo {
private: 
  int a,b;
public:
  Foo(int c, int d)  : a(c), b(d) {}
  Foo(const Foo & X) : a(X.a), b(X.b) {}
  Foo& operator=(const Foo& X) {
    if (this == &X) return *this;
    a = X.a;
    b = X.b;
    return *this;
  }
};
如果一个类有中等数量的数据成员,那么有三个地方可以将不同的赋值/初始化搞得一团糟。我的意思是,如果复制构造函数看起来像:

  Foo(const Foo & X) : a(X.a), b(X.a) {}
或者运算符“”缺少一行。由于赋值运算符和复制构造函数通常具有相同的效果(因为我们将成员从一个Foo复制到另一个Foo),我可以“重用”复制构造函数或赋值运算符中的代码吗?反之亦然

因为赋值运算符和复制构造函数通常具有相同的效果

一点也不,一个执行初始化,另一个执行赋值。它们在对象的初始状态中是不同的,并且它们的任务是分开的(尽管相似)。规范赋值运算符通常按以下方式执行:

Foo& operator=(Foo right) {
    right.swap( *this );
    return *this;
}

您的目标应该是根本不编写复制构造函数/赋值运算符。您的目标应该是让编译器来完成。标准库容器都是可复制的,所以在合理的地方使用它们

如果存在无法正确复制的成员,请使用智能指针或其他RAII对象。这些对象应该需要特殊的复制构造函数/赋值。而且他们只需要他们的一个成员


其他所有内容都不应使用它们。

将所有内容转发给赋值运算符可能无效,但这是C++03中允许的命令

在C++11中,构造函数更容易:将所有构造函数转发给一个主构造函数

class Foo {
private: 
  int a,b;
public:
  Foo(int c, int d)  : a(c), b(d) {}
  Foo(const Foo & X) : Foo(x.a, x.d) {} 
  //syntax may be wrong, I don't have a C++11 compiler
  Foo& operator=(const Foo& X) {
    if (this == &X) return *this;
    a = X.a;
    b = X.b;
    return *this;
  }
}
在C++03中(如果允许)


但请记住,这不能用于某些常见情况。(任何不可赋值的对象)

获得正确的复制构造函数和赋值运算符比看起来要困难得多;你真的应该读这本书。另一方面,正如other所说,在这种情况下,不需要用户声明的复制构造函数和赋值运算符@freerider:一般来说,如果您的类管理
操作符=
在复制之前需要释放的资源,那么这不是一个好主意。@matteo italia:我知道,但我刚刚回答了本例中不包含堆分配的问题。当然,您不应该在更复杂的类中使用构造函数。构造函数很常见,可以提供很多选项。不过我同意赋值。@MooingDuck:但是复制构造函数可以留给编译器来编写(如果让编译器编写复制赋值运算符是安全的,至少应该是安全的)。
…=违约是你的朋友;使用它。@MooingDuck编译器,即使是VC2010,也会尽可能为您创建一个复制构造函数和复制赋值运算符。只有当您的成员没有复制构造函数/赋值时才会出现这种情况。@MooingDuck:为什么?只要让编译器生成的构造函数做正确的事情,即使定义了其他构造函数,也不必定义它。
class Foo {
private: 
  int a,b;
  void init(int c, int d) {a=c; b=d;}
public:
  Foo(int c, int d)  : {init(c,d);}
  Foo(const Foo & X) : {init(X.a, X.b);} 
  Foo& operator=(const Foo& X) { init(X.a, X.b);} 
}