繁体   English   中英

什么是四规则(半规则)?

[英]What is the Rule of Four (and a half)?

为了正确处理 object 复制,经验法则是三法则 对于 C++11,移动语义是一回事,所以它是五法则 但是,在这里和互联网上的讨论中,我还看到了对四规则(半)的引用,它是五规则和复制和交换习语的组合。

那么究竟什么是四法则(半法则)? 需要实现哪些功能,每个功能的主体应该是什么样的? 哪个function是一半? 与五法则相比,这种方法有什么缺点或警告吗?

这是一个类似于我当前代码的参考实现。 如果这是不正确的,正确的实现会是什么样子?

//I understand that in this example, I could just use `std::unique_ptr`.
//Just assume it's a more complex resource.
#include <utility>

class Foo {
public:
    //We must have a default constructor so we can swap during copy construction.
    //It need not be useful, but it should be swappable and deconstructable.
    //It can be private, if it's not truly a valid state for the object.
    Foo() : resource(nullptr) {}

    //Normal constructor, acquire resource
    Foo(int value) : resource(new int(value)) {}

    //Copy constructor
    Foo(Foo const& other) {
        //Copy the resource here.
        resource = new int(*other.resource);
    }

    //Move constructor
    //Delegates to default constructor to put us in safe state.
    Foo(Foo&& other) : Foo() {
        swap(other);
    }

    //Assignment
    Foo& operator=(Foo other) {
        swap(other);
        return *this;
    }

    //Destructor
    ~Foo() {
        //Free the resource here.
        //We must handle the default state that can appear from the copy ctor.
        //(The if is not technically needed here. `delete nullptr` is safe.)
        if (resource != nullptr) delete resource;
    }

    //Swap
    void swap(Foo& other) {
        using std::swap;

        //Swap the resource between instances here.
        swap(resource, other.resource);
    }

    //Swap for ADL
    friend void swap(Foo& left, Foo& right) {
        left.swap(right);
    }

private:
    int* resource;
};

那么四分之一(一半)究竟是什么呢?

“四大(一半)规则”指出,如果你实施其中一个

  • 复制构造函数
  • 赋值运算符
  • 移动构造函数
  • 析构函数
  • 交换功能

那么你必须有一个关于其他人的政策。

需要实现哪些功能,每个功能的主体应该是什么样的?

  • 默认构造函数(可以是私有的)
  • 复制构造函数(这里有真正的代码来处理你的资源)
  • 移动构造函数(使用默认构造函数和交换):

     S(S&& s) : S{} { swap(*this, s); } 
  • 赋值运算符(使用构造函数和交换)

     S& operator=(S s) { swap(*this, s); } 
  • 析构函数(资源的深层副本)

  • friend swap(没有默认实现:/你应该想要交换每个成员)。 这一点与swap成员方法相反: std::swap使用move(或copy)构造函数,这将导致无限递归。

一半的功能是什么?

从上一篇文章:

“为了实现Copy-Swap习惯用法,你的资源管理类还必须实现一个swap()函数来执行逐个成员的交换(这是你的”......(和一半)“)

所以swap方法。

与五法则相比,这种方法有任何缺点或警告吗?

我已经写过的警告是要编写正确的交换以避免无限递归。

与五法则相比,这种方法有任何缺点或警告吗?

虽然它可以节省代码重复,但使用复制和交换只会导致更糟糕的类,更直接。 你正在伤害你的班级表现,包括移动任务(如果你使用统一分配操作员,我也不是它的粉丝),这应该非常快。 作为交换,您将获得强大的异常保证,这在一开始看起来不错。 问题是,您可以通过简单的通用函数从任何类中获得强大的异常保证:

template <class T>
void copy_and_swap(T& target, T source) {
    using std::swap;
    swap(target, std::move(source));
}

就是这样。 因此,需要强大异常安全的人无论如何都可以获得它。 坦率地说,强大的异常安全无论如何都是一个利基市场。

保存代码重复的真正方法是通过Zero of Zero:选择成员变量,这样就不需要编写任何特殊功能。 在现实生活中,我会说90%以上的时间我看到特殊的会员功能,他们可以很容易地避免。 即使你的类确实有某种一个特殊的成员函数需要特殊的逻辑,你通常是关闭向下推到一个成员更好。 您的记录器类可能需要在其析构函数中刷新缓冲区,但这不是编写析构函数的理由:编写一个处理刷新的小缓冲区类,并将其作为记录器的成员。 记录器可能具有可以自动处理的各种其他资源,并且您希望让编译器自动生成复制/移动/破坏代码。

关于C ++的事情是每个函数自动生成特殊函数是全部或全部。 这就是拷贝构造函数(如)要么被自动生成的,同时考虑到所有成员,或者你必须手工编写(更糟的是,维持)这一切 所以它强烈推动你采取一种向下推动事物的方法。

如果您正在编写一个类来管理资源并需要处理它,通常应该是:a)相对较小,b)相对通用/可重用。 前者意味着一些重复的代码并不是什么大问题,而后者意味着您可能不希望将性能留在桌面上。

总而言之,我强烈反对使用复制和交换,以及使用统一赋值运算符。 尝试遵循零规则,如果你不能,遵循五法则。 只有当你可以使它比通用交换(执行3次移动)更快时才写swap ,但通常你不需要打扰。

简单来说,只要记住这一点。

0 规则

Classes have neither custom destructors, copy/move constructors or copy/move assignment operators.

规则 3 :如果您实现了其中任何一个的自定义版本,那么您就实现了所有这些。

Destructor, Copy constructor, copy assignment

5 规则:如果您实现自定义移动构造函数或移动赋值运算符,则需要定义所有 5 个。 需要移动语义。

Destructor, Copy constructor, copy assignment, move constructor, move assignment

四个半规则:与规则 5 相同,但具有复制和交换习语。 通过包含交换方法,复制赋值和移动赋值合并为一个赋值运算符。

Destructor, Copy constructor, move constructor, assignment, swap (the half part)

Destructor: ~Class();
Copy constructor: Class(Class &);
Move constructor: Class(Class &&);
Assignment: Class & operator = (Class);
Swap: void swap(Class &);

没有警告,优点是分配速度更快,因为按值复制实际上比在方法主体中创建临时 object 更有效。

现在我们有了临时 object,我们只需对临时 object 执行交换。 当它超出 scope 时,它会自动销毁,现在我们在 object 中拥有运算符右侧的值。

参考资料

https://www.linkedin.com/learning/c-plus-plus-advanced-topics/rule-of-five?u=67551194 https://en.cppreference.com/w/cpp/language/rule_of_three

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM