【问题标题】:Initializer lists: copy constructors and assignment operators = redundancy?初始化列表:复制构造函数和赋值运算符 = 冗余?
【发布时间】:2011-12-24 20:18:18
【问题描述】:

对于您的类构造函数,初始化列表似乎是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) {}

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

【问题讨论】:

  • 获得正确的复制构造函数和赋值运算符比看起来要困难得多;你真的应该阅读FAQ on the copy-and-swap idiom。另一方面,正如其他人所说,在这种情况下,不需要用户声明的复制构造函数和赋值运算符。
  • 我通常在构造函数中使用operator=:Foo(const Foo & X){ *this = X;}
  • @freerider:一般来说,如果你的班级管理operator=在复制之前需要释放的资源,这不是一个好主意。
  • @matteo italia:我知道,但我刚刚回答了这个示例中不包含堆分配的问题。当然你不应该在更复杂的类中使用。

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


【解决方案1】:

将所有内容转发给赋值运算符可能无效,但这在允许的 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 中(允许的地方)

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

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 构造函数很常见,可以做出很多选择。不过我同意分配。
    • @MooingDuck:但是 copy 构造函数可以留给编译器编写(至少如果让编译器编写复制赋值运算符是安全的,它应该是安全的) .
    • ... = default; 是你的朋友;使用它。
    • @MooingDuck 编译器,甚至是 VC2010,都会尽可能为你创建一个拷贝构造函数和拷贝赋值运算符。唯一不会的情况是您的成员没有复制构造函数/赋值。
    • @MooingDuck:为什么?只需要让编译器生成一个做正确的事,即使你定义了其他构造函数,你也不必定义它。
    【解决方案3】:

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

    一点也不,一个做初始化,另一个做赋值。它们在对象的初始状态上是不同的,它们的任务是分开的(尽管相似)。规范赋值运算符通常是这样完成的:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      • 1970-01-01
      • 2013-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多