为什么三规则中不考虑非默认构造函数?

发布于 2024-12-08 03:43:12 字数 156 浏览 3 评论 0原文

三法则(也称为三巨头定律或三巨头法则)是 C++ 中的一条经验法则,它声称如果一个类定义了以下其中一项,那么它可能应该显式定义所有三项:析构函数、复制构造函数、复制赋值运算符。

为什么非默认构造函数不被视为其中之一?当类中管理任何资源时,程序员无论如何都必须定义一个非默认构造函数。

The rule of three (also known as the Law of The Big Three or The Big Three) is a rule of thumb in C++ that claims that if a class defines one of the following it should probably explicitly define all three: destructor, copy constructor, copy assignment operator.

Why is a non-default constructor not considered as one of them? When there is any resource managed in the class, programmer has to define a non-default constructor anyway.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

醉梦枕江山 2024-12-15 03:43:12

为什么非默认构造函数不被视为其中之一?当类中管理任何资源时,程序员无论如何都必须定义一个非默认构造函数。

这不一定是真的。构造函数可能不会获取任何资源。其他功能也可能获取它们。事实上,可能有许多函数(包括构造函数本身)可能获取资源。例如,在 std::vector 的情况下,需要resize()reserve() /em> 资源。因此,请考虑构造函数就像其他可能获取资源的函数一样。

该规则的想法是,当您进行复制时,编译器生成的默认复制代码将不起作用。因此,您需要自己编写复制语义。由于类管理资源(哪个函数获取它并不重要),析构函数必须释放它,因为析构函数保证被执行,对于一个完全构建的对象。因此,您还必须定义析构函数。在 C++11 中,您还必须实现移动语义。 move-semantic 的逻辑论证与 copy-semantics 的逻辑论证相同,除了在 move-semantic 中,您也更改了。移动语义很像器官捐赠者;当你把你的器官捐给别人时,你就不再拥有它了。

Why is a non-default constructor not considered as one of them? When there is any resource managed in the class, programmer has to define a non-default constructor anyway.

That is not necessarily true. The constructor might not aquire any resource. Other function(s) might aquire them as well. In fact, there can be many functions (including the constructor(s) themselves) which might aquire resources. For example, in case of std::vector<T>, it is resize() and reserve() which aquire resources. So think of constructor(s) just like other function(s) which might aquire resources.

The idea of this rule is that when you make a copy, the default-copy code generated by the compiler wouldn't work. Hence you need to write the copy-semantic yourself. And since the class manages resources (it doesn't matter which function(s) aquire it), the destructor must release it, because the destructor is guaranteed to be executed, for a fully constructed object. Hence you've to define the destructor as well. And in C++11, you've to implement move-semantics as well. The logical argument for move-semantic is same as that of copy-semantics, except that in move semantic, you changed the source as well. Move-semantic is much like organ-donor; when you give your organ to other, you don't own it anymore.

梦断已成空 2024-12-15 03:43:12

这不是三人法则的意义所在。

任何管理资源的类都将具有该析构函数,因此无论如何,三规则都适用。要点是,您绝对不需要非默认构造函数,但您确实需要其他构造函数(复制构造函数/赋值运算符)。

至少它曾经对于标准容器中的元素等至关重要。

现在有了移动语义 (c++11),事情开始发生一些变化。会有5的规则吗?我不知道它在“最佳实践”和“经验法则”方面会如何表现。

事实上,我们已经可以陈述“三法则”的一种变体:定义析构函数的类还应该定义复制/移动构造函数和复制/移动赋值运算符。 AND 如果定义了复制构造函数,则还应该定义复制赋值运算符。 AND 如果定义了移动构造函数,则还应该定义移动赋值运算符。

无论如何,这将是我一段时间内的经验法则。

That's not what the rule of three is about.

Any class that manages resources will have that destructor, and hence the rule of three applies anyway. The point is that you don't absolutely need non-default constructors, but you do need the others (copy constructor / assignment operator).

At least it used to be vital for e.g. elements in standard containers.

Now with move semantics (c++11), things are starting to shift a bit. Will there be a rule of 5? I don't know how it will pan out in terms of 'best practices' and 'rules of thumb'.

In fact one could state a variation of the Rule of Three already: a class that defines a destructor should also define a copy/move constructor and copy/move assignment operator. AND if a copy constructor is defined, a copy assignment operator should also be defined. AND if a move constructor is defined, a move assignment operator should also be defined.

This is going to be my rule of thumb for a while, anyways.

离笑几人歌 2024-12-15 03:43:12

如果您获取任何资源(例如使用 new ),您是完全正确的,但假设您不会忘记在析构函数中释放资源。创建析构函数后,三个规则就会生效,您应该定义所有三个。

但是,例如,如果您的类中只有一些使用复制语义初始化的成员变量,则不需要析构函数,并且该规则不适用。

If you aquire any resources (eg with new) you are quite right, but it is assumed that you don't forget to release the resources in the destructor. Once you created the destructor the rule of three kicks in and you should define all three.

However, if for example you only have some member variables in your class that you initialize with copy semantics you don't need the destructor and the rule doesn't apply.

绝不放开 2024-12-15 03:43:12

定义非默认构造函数并不自动意味着您需要析构函数等 - 您可能只是使用该构造函数来方便填充 POD 类型。

也就是说,这同样适用于默认构造函数。

基本上,“你需要三巨头吗?”当类将管理资源时触发。您可能仍然不需要默认构造函数,但您确实需要一个构造函数来设置有效的初始状态。

新构造的状态可能还不拥有该资源的实例,但如果它不拥有,那么它必须知道它不拥有(例如,有一个空指针)。

然而,在很多情况下,三巨头也被隐含地使用。例如,临时变量是默认构造的。您需要非默认构造函数的原因之一就是阻止提供和使用隐式默认构造函数。

因此,同时定义所有三个的原因之一是确保您的代码(包括编译器隐式提供的代码)保持健全。

几乎总是,如果您管理资源,您将有一个默认构造函数,这就是规则提到这一点的原因 - 但只要您定义某种构造函数,就应该没问题。

Defining a non-default constructor doesn't automatically mean you need a destructor etc - you may just be using that constructor as a convenience to fill in a POD type.

That said, the same applies to default constructors.

Basically, the "do you need the big three?" is triggered when the class will manage a resource. You still might not need a default constructor, but you do need a constructor to set up a valid initial state.

That newly-constructed state may not own an instance of the resource yet, but if it doesn't, then it must know that it doesn't (e.g. have a null pointer).

However, the big three are also used implicitly in a lot of cases. Temporaries, for example, are default-constructed. One reason you would need a non-default constructor is simply to block the implicit default constructor from being provided and used.

So one reason to define all three at once is to ensure that your code (including that provided implicitly by the compiler) remains sane.

Almost always, if you're managing a resource, you will have a default constructor, so that's why the rule mentions that - but so long as you define some kind of constructor, you should be OK.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文