初始化器列表:复制构造函数和赋值运算符=冗余?

时间:2011-11-08 21:51:33

标签: c++ copy-constructor assignment-operator initialization

对于你的类构造函数来说,initalizer列表似乎是good idea,我也假设,对于复制构造函数也是如此。对于赋值运算符,必​​须在函数体中分配每个成员。考虑以下简单的块:

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),我可以“重用”复制构造函数或赋值运算符中的代码,反之亦然吗?

3 个答案:

答案 0 :(得分:10)

您的目标应该是不要编写复制构造函数/赋值运算符。你的目标应该是让编译器去做。标准库容器都是可复制的,因此在合理的情况下使用它们。

如果有成员无法正确复制,则使用智能指针或其他RAII对象。那些对象是需要特殊拷贝构造函数/赋值的对象。他们只需要他们的一个成员。

其他一切都不应该使用它们。

答案 1 :(得分:3)

  

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

完全没有,一个进行初始化而另一个进行分配。它们在对象的初始状态不同,它们的任务是分开的(虽然相似)。规范赋值运算符通常用:

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

答案 2 :(得分:2)

将all转发给赋值运算符可能无效,但这是允许在C ++ 03中的commmon。

在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中(允许)

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);} 
}

但请记住,不能在某些常见情况下使用。 (任何不可分配的对象)