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

Which copy/move constructor/operator to define for simple structures?

本文关键字:移动 构造函数 运算符 复制 简单 结构 定义      更新时间:2023-10-16

我的程序使用一个简单的结构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;
    }

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

是的(在你的例子中)。请参阅C++11标准(第12条),或文章"隐式移动不会成功!"!(结尾处的图表很漂亮)。综上所述(并简化),以下所有特殊成员函数都将自动生成(隐式声明并定义为默认值):

  • 析构函数–因为您没有声明它
  • 复制构造函数–因为您没有声明它,也没有声明任何MC和MAO
  • 复制分配运算符–因为您没有声明它,也没有声明任何MC和MAO
  • 移动构造函数–因为您既没有声明它,也没有声明D、CC、CAO和MAO中的任何一个
  • 移动分配运算符–因为您既没有声明它,也没有声明D、CC、CAO和MC中的任何一个

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

Q2:自动生成的函数是否正确

是的(在你的例子中)。所有的数据成员(这里是普通的int)都有正确的复制/移动语义(他们的复制/移动构造函数和赋值运算符做了正确的事情,而那些为Rect自动生成的将调用它们)。

Q3:不管怎样,你应该手动定义它们吗

我认为它(在您的示例中)没有优势,也没有潜在的问题(如在您的实例中,请参阅注释)。

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

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

如果您出于某些原因想要详细说明,您可以将它们声明为默认的自文档,如下所示:

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

还注意到,由于委托构造函数

,默认构造函数重用了完整的构造函数