提问人: 提问时间:7/9/2017 更新时间:7/10/2017 访问量:4574
零法则混乱?
Rule of Zero confusion?
问:
所以我一直在阅读关于零法则的文章。
简体版:我不明白这条规则的目的是什么。三和五法则有点像“经验法则”,但我看不出“经验法则”或这条规则的任何其他具体意图。
详细版本:
让我引用:
具有自定义析构函数、复制/移动构造函数或 复制/移动分配操作员应专门处理所有权。 其他类不应有自定义析构函数,复制/移动 构造函数或复制/移动赋值运算符。
这是什么意思?他们所说的所有权,所有权是什么意思? 他们还展示了一个示例代码(我猜它与介绍有关):
class rule_of_zero
{
std::string cppstring;
public:
rule_of_zero(const std::string& arg) : cppstring(arg) {}
};
他们想用这个展示什么,我真的迷失了这个。
此外,他们还讨论了当您处理多态类并且析构函数被声明为公共和虚拟时的场景,以及该块隐式移动的事实。因此,您必须将它们全部声明为默认值:
class base_of_five_defaults
{
public:
base_of_five_defaults(const base_of_five_defaults&) = default;
base_of_five_defaults(base_of_five_defaults&&) = default;
base_of_five_defaults& operator=(const base_of_five_defaults&) = default;
base_of_five_defaults& operator=(base_of_five_defaults&&) = default;
virtual ~base_of_five_defaults() = default;
};
这是否意味着,每当你有一个基类,其析构函数同时声明为公共和虚拟时,你真的必须将所有其他特殊成员函数声明为默认值?如果是这样,我不明白为什么。
我知道这在一个地方有很多混乱。
答:
零法则
零法则是关于如何编写需要使用某些资源(如内存或其他对象)的类的另一个经验法则。在此示例中,包含字符串字符的动态分配内存是必须管理的资源。
建议让专门的类管理资源,并且只这样做。在此示例中,std::string 负责管理分配的内存的所有详细信息。
该规则是在 C++11 引入后出现的,因为语言和标准库得到了改进,为管理动态分配的对象生存期(unique_ptr 和 shared_ptr)提供了更好的工具。此外,容器现在允许就地构建,从而消除了动态分配的另一个原因。它可能应该被看作是对更古老的三规则的更新。
因此,如果您以前在构造函数中使用 new 来创建某个成员并在析构函数中删除,那么现在应该使用unique_ptr来管理成员的生存期,从而“免费”获得移动构造和移动分配。
共享指针可以记住要调用的正确析构函数,因此对于通过共享指针独占管理的对象,即使它们以多态方式使用,对虚拟析构函数的常见需求也消失了。
因此,基本上一个可以依赖其成员来执行初始化、移动、复制和销毁所需的所有操作的类不应该声明任何特殊的成员函数。
五法则
与C++一样,事情并不总是那么简单。
正如 Scott Meyers 所指出的,如果出于某种原因必须添加析构函数,则移动构造函数和移动赋值运算符的隐式生成将被禁用,即使编译器可以生成它们。
然后编译器会愉快地将你的类复制到各处,而不是移动它,这可能不是你所期望的。例如,这可能会减慢您的程序速度,因为必须执行更多的复制。默认情况下,编译器不会对此发出警告。
因此,他建议明确指定您想要五种特殊方法中的哪一种,以避免由于不相关的更改而出现意外。他仍然建议编写非资源管理类,以便可以使用编译器生成的默认值。
上一个:复制构造函数和赋值运算符
下一个:零规则与基类析构函数
评论