讨论:保持定义复制,移动和析构函数的一致性
???
Note(注意)
If you define a copy constructor, you must also define a copy assignment operator.
如果定义了拷贝构造函数,则还必须定义一个拷贝赋值运算符。
Note(注意)
If you define a move constructor, you must also define a move assignment operator.
如果定义了移动构造函数,则还必须定义一个移动赋值运算符。
Example(示例)
class X {
public:
X(const X&) { /* stuff */ }
// BAD: failed to also define a copy assignment operator
X(x&&) noexcept { /* stuff */ }
// BAD: failed to also define a move assignment operator
// ...
};
X x1;
X x2 = x1; // ok
x2 = x1; // pitfall: either fails to compile, or does something suspicious
If you define a destructor, you should not use the compiler-generated copy or move operation; you probably need to define or suppress copy and/or move.
如果定义了析构函数,则不应使用编译器生成的复制或移动操作。您可能需要定义或抑制复制和/或移动操作。
class X {
HANDLE hnd;
// ...
public:
~X() { /* custom stuff, such as closing hnd */ }
// suspicious: no mention of copying or moving -- what happens to hnd?
};
X x1;
X x2 = x1; // pitfall: either fails to compile, or does something suspicious
x2 = x1; // pitfall: either fails to compile, or does something suspicious
If you define copying, and any base or member has a type that defines a move operation, you should also define a move operation.
如果您在定义拷贝操作,如果任何基类或成员的类型具有移动操作,则还应该定义移动操作。
class X {
string s; // defines more efficient move operations
// ... other data members ...
public:
X(const X&) { /* stuff */ }
X& operator=(const X&) { /* stuff */ }
// BAD: failed to also define a move construction and move assignment
// (why wasn't the custom "stuff" repeated here?)
};
X test()
{
X local;
// ...
return local; // pitfall: will be inefficient and/or do the wrong thing
}
If you define any of the copy constructor, copy assignment operator, or destructor, you probably should define the others.
如果定义了拷贝构造函数,拷贝赋值运算符或析构函数中的任何一个,则可能应该定义其他所有函数。
Note(注意)
If you need to define any of these five functions, it means you need it to do more than its default behavior -- and the five are asymmetrically interrelated. Here's how:
如果您需要定义这五个函数中的任何一个,则意味着您需要它做更多的工作而不是其默认行为-并且这五个函数是不对称地相互关联的。就是这样:
In many cases, holding properly encapsulated resources using RAII "owning" objects can eliminate the need to write these operations yourself. (See Item 13.)
在许多情况下,使用RAII“拥有”对象保存正确封装的资源可以消除自己编写这些操作的需要。(请参阅第13项。)
Prefer compiler-generated (including =default) special members; only these can be classified as "trivial", and at least one major standard library vendor heavily optimizes for classes having trivial special members. This is likely to become common practice.
首选编译器生成的(包括= default)特殊成员;只有这些可以归类为“琐碎的”,并且至少一个主要的标准库供应商针对具有琐碎的特殊成员的类进行了重度优化。这很可能会成为惯例。
Exceptions: When any of the special functions are declared only to make them non-public or virtual, but without special semantics, it doesn't imply that the others are needed. In rare cases, classes that have members of strange types (such as reference members) are an exception because they have peculiar copy semantics. In a class holding a reference, you likely need to write the copy constructor and the assignment operator, but the default destructor already does the right thing. (Note that using a reference member is almost always wrong.)
例外:当声明任何特殊函数只是为了使它们成为非公共或虚拟的,而没有特殊语义时,并不意味着需要其他特殊功能。在极少数情况下,具有奇怪类型的成员(例如引用成员)的类是例外,因为它们具有特殊的复制语义。在一个包含引用的类中,您可能需要编写拷贝构造函数和赋值运算符,但是默认的析构函数已经可以正确处理。(请注意,使用引用成员几乎总是错误的。)
Resource management rule summary:
资源管理规则摘要:
原文链接https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#define-copy-move-and-destroy-consistently