C++核心准则​讨论:保持定义复制,移动和析构函数的一致性

网友投稿 768 2022-10-13

C++核心准则​讨论:保持定义复制,移动和析构函数的一致性

C++核心准则​讨论:保持定义复制,移动和析构函数的一致性

Discussion: Define Copy, move, and destroy consistently

讨论:保持定义复制,移动和析构函数的一致性

Reason(原因)

-

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; // okx2 = 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 suspiciousx2 = 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:

如果您需要定义这五个函数中的任何一个,则意味着您需要它做更多的工作而不是其默认行为-并且这五个函数是不对称地相互关联的。就是这样:

If you write/disable either of the copy constructor or the copy assignment operator, you probably need to do the same for the other: If one does "special" work, probably so should the other because the two functions should have similar effects. (See Item 53, which expands on this point in isolation.)如果您编写/禁用了拷贝构造函数或拷贝赋值运算符,则可能需要对另一个函数进行相同的操作:如果一个函数执行“特殊”工作,那么另一个函数也应该这样做,因为这两个函数应具有相似的效果。(请参阅第53项,它在这一点上单独展开。)If you explicitly write the copying functions, you probably need to write the destructor: If the "special" work in the copy constructor is to allocate or duplicate some resource (e.g., memory, file, socket), you need to deallocate it in the destructor.如果您显式地编写拷贝函数,则可能需要编写析构函数:如果拷贝构造函数中的“特殊”工作是分配或拷贝某些资源(例如,内存,文件,套接字),则需要在析构函数中释放它。If you explicitly write the destructor, you probably need to explicitly write or disable copying: If you have to write a non-trivial destructor, it's often because you need to manually release a resource that the object held. If so, it is likely that those resources require careful duplication, and then you need to pay attention to the way objects are copied and assigned, or disable copying completely.如果显式地编写了析构函数,则可能需要显式地编写或禁用拷贝操作:如果必须编写非平凡的析构函数,通常是因为您需要手动释放对象持有的资源。如果是这样,则这些资源可能需要仔细复制,然后您需要注意复制和分配对象的方式,或者完全禁用复制。

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:

资源管理规则摘要:

Provide strong resource safety; that is, never leak anything that you think of as a resource提供强大的资源安全性;也就是说,永远不要泄漏任何您认为是资源的东西Never throw while holding a resource not owned by a handle持有没有被句柄拥有的资源时切勿抛出异常A "raw" pointer or reference is never a resource handle“原始”指针或引用绝不是资源句柄Never let a pointer outlive the object it points to永远不要让指针值的生命周期超过它所指向的对象Use templates to express containers (and other resource handles)使用模板来表达容器(和其他资源句柄)Return containers by value (relying on move or copy elision for efficiency)按值返回容器(依靠移动或复制省略以提高效率)If a class is a resource handle, it needs a constructor, a destructor, and copy and/or move operations如果类是资源句柄,则它需要一个构造函数,一个析构函数以及复制和/或移动操作If a class is a container, give it an initializer-list constructor如果类是容器,请为其提供一个初始化器列表形式的构造函数

原文链接​​的标准GUI 工具包tkinter,通过可执行的示例对23 个设计模式逐个进行说明。这样一方面可以使读者了解真实的软件开发工作中每个设计模式的运用场景和想要解决的问题;另一方面通过对这些问题的解决过程进行说明,让读者明白在编写代码时如何判断使用设计模式的利弊,并合理运用设计模式。

对设计模式感兴趣而且希望随学随用的读者通过本书可以快速跨越从理解到运用的门槛;希望学习Python GUI 编程的读者可以将本书中的示例作为设计和开发的参考;使用Python 语言进行图像分析、数据处理工作的读者可以直接以本书中的示例为基础,迅速构建自己的系统架构。

觉得本文有帮助?请分享给更多人。

面向对象开发,面向对象思考!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:r2 类似unix的逆向工程框架和命令行工具
下一篇:自学HarmonyOS应用开发(65)- 为Tab组件使用图像资源
相关文章

 发表评论

暂时没有评论,来抢沙发吧~