为简单结构定义哪个复制/移动构造函数/运算符?

时间:2013-08-31 12:06:56

标签: c++ c++11 copy-constructor move-semantics assignment-operator

我的程序使用一个简单的结构Rect,定义为

struct Rect {
    int x1, y1, x2, y2;

    Rect()
    : x1(0), y1(0), x2(0), y2(0) { }

    Rect(int x1, int y1, int x2, int y2)
    : x1(x1), y1(y1), x2(x2), y2(y2) { }
};

我应该定义复制/移动构造函数还是赋值运算符,还是可以依靠编译器自动生成它们?问题在于速度和使用原因(例如,移动构造函数可以影响程序执行速度)。

构造函数和运算符是非常重复的工作,所以如果我可以依靠编译器自动生成它们,它会很好。

    Rect(const Rect& r)
    : x1(r.x1), y1(r.y1), x2(r.x2), y2(r.y2) { }

    Rect(Rect&& r)
    : x1(r.x1), y1(r.y1), x2(r.x2), y2(r.y2) { }

    Rect& operator = (const Rect& r) {
        x1 = r.x1;
        y1 = r.y1;
        x2 = r.x2;
        y2 = r.y2;
    }

4 个答案:

答案 0 :(得分:6)

Q1:你能依靠编译器自动生成那些吗?

是(在您的示例中)。请参阅C ++ 11标准(第12节)或文章Implicit Move Won’t Go!(接近结尾的好图表)。总结(和简化),将自动生成以下所有特殊成员函数(隐式声明并定义为默认):

  • 析构函数 - 因为您没有声明它。
  • 复制构造函数 - 因为您没有声明它,也没有声明MC和MAO。
  • 复制分配操作员 - 因为您没有声明它,也没有声明MC和MAO。
  • 移动构造函数 - 因为您没有声明它,也没有声明D,CC,CAO和MAO。
  • 移动分配操作员 - 因为您没有声明它,也没有声明D,CC,CAO和MC。

(我使用丑陋的首字母只是为了使每个列表项保持一行。)除了上面的“因果”之外,对于除了析构函数之外的所有内容,还有一个额外的约束,即生成的默认值必须有意义,即所有数据成员必须是可复制的(对于CC和CAO)或可移动的(对于MC和MAO)。 (实际上,准确的规则有点复杂,但我不想在这里重新标注。)

Q2:自动生成的功能是否正确?

是(在您的示例中)。所有数据成员(此处为普通int)都具有正确的复制/移动语义(他们的复制/移动构造函数和赋值运算符做正确的事情,以及为{{1}自动生成的那些会调用它们。)

问题3:无论如何,你应该手动定义它们吗?

我认为没有优势(在您的示例中)和潜在问题(如您的示例所示,请参阅评论)。

答案 1 :(得分:1)

您可以在编译器上进行中继,因为您的数据成员是内置类型,因此可以通过成员副本创建对象的副本。如果您不定义复制/移动构造函数或赋值运算符,则会出现这种情况。如果您有一个指针作为数据成员,则可能需要它们。

答案 2 :(得分:1)

你不需要为显式复制构造函数编写一个赋值,因为你的struct Rect的成员都是c ++ buildin类型,所以编译器会生成一个按位复制构造函数。在你的代码中,我认为你可以依赖你的编译器完全。

答案 3 :(得分:1)

如果您因某些原因想要冗长,可以将它们声明为默认为自我记录,如下所示:

struct Rect {
    int x1, y1, x2, y2;

    Rect () : Rect( 0, 0, 0, 0 ) { }

    Rect ( int x1, int y1, int x2, int y2 )
    : x1(x1), y1(y1), x2(x2), y2(y2) { }

    // Rect is Copy/Move Constructible and Assignable
    Rect( Rect const & ) = default;
    Rect( Rect && ) = default;
    Rect& operator= ( Rect const & ) = default;
    Rect& operator= ( Rect && ) = default;
};

还要注意默认构造函数重用完整的构造函数,这要归功于委托构造函数