智能指针如何影响 5 法则?

How do smart pointers affect the rule of 5?

提问人:CiaranWelsh 提问时间:4/15/2020 更新时间:4/15/2020 访问量:933

问:

我了解到,当你在课堂上使用指针时,你应该实现 5 规则。如果你不使用指针,那么你可以,事实上,最好使用默认值。但是,这如何与智能指针配合使用?例如,包含 的类可能如下所示:int*

class A {
private:
    int *num_;
public:

    explicit A(int* num) : num_(num) {}

    ~A() {
        delete num_;
    }

    A(const A &other) {
        if (this != &other) {
            num_ = other.num_;
        }
    }

    A(A &&other) noexcept {
        if (this != &other) {
            num_ = other.num_;
        }
    }

    A &operator=(A &other) {
        if (this == &other) {
            this->num_ = other.num_;
        }
        return *this;
    }

    A &operator=(A &&other) noexcept {
        if (this == &other) {
            this->num_ = other.num_;
        }
        return *this;
    };


};

但是,如果我们使用智能指针,仅仅这样做就足够了吗?

class B {
private:
    std::unique_ptr<int> num_;

public:

    explicit B(int num) : num_(std::make_unique<int>(num)) {};

};
C++ 智能指针 则 五法则

评论

2赞 UnholySheep 4/15/2020
请注意,这些示例不会执行相同的操作,因为第二个示例将隐式删除复制构造函数和赋值运算符,因为这些示例是不可复制的std::unique_ptr
0赞 CiaranWelsh 4/15/2020
啊,这是有道理的。那么我应该使用一个吗?std::shared_ptr
0赞 Caleth 4/15/2020
这取决于你是否想要可复制(两者都是可移动的)BAB
0赞 463035818_is_not_an_ai 4/15/2020
@CiaranWelsh这不应该成为您选择智能指针类型的理由。相反:您是否需要共享所有权。没有共享所有权(至少没有正确;)A
1赞 463035818_is_not_an_ai 4/15/2020
我想这是一个错别字:if (this == &other) {

答:

1赞 Jean-Marc Volle 4/15/2020 #1

如果使用智能指针(或任何 std:: 容器),则类默认析构函数将调用智能指针(和容器)的析构函数。 有关此主题的更多信息,请参阅:为什么 C++ 默认析构函数不会销毁我的对象?

4赞 463035818_is_not_an_ai 4/15/2020 #2

是的,这就足够了。唯一指针确实管理内存。但是,由于无法复制 std::unique_ptr,因此不会有编译器生成的复制构造函数或赋值。B

另请注意,您实现了 5 规则的所有方法,但未正确实现。正如注释中提到的,复制将导致两个实例具有相同的指针,并在销毁时将其删除。实际上,正确处理这一点是关于 3/5 规则的重点,也是为什么你应该更喜欢 0 规则。A

2赞 Caleth 4/15/2020 #3

它们有不同的行为。 可以复制,只能移动。AB

注意,您的实施是不安全的,它可能导致泄漏和未定义的行为。A

同类的比较将是 的副本deleteA

class A {
private:
    int *num_;
public:

    explicit A(int num) : num_(new int(num)) {}

    ~A() {
        delete num_;
    }

    A(const A &other) = delete;

    A(A &&other) noexcept 
     : num_(std::exchange(other.num, nullptr)) {}

    A &operator=(const A &other) =delete;

    A &operator=(A &&other) noexcept {
        swap(num_, other.num_);
        return *this;
    };
};

class B {
private:
    std::unique_ptr<int> num_;

public:

    explicit B(int num) : num_(std::make_unique<int>(num)) {};

};

或者定义 的 copyB

class A {
private:
    int *num_;
public:

    explicit A(int num) : num_(new int(num)) {}

    ~A() {
        delete num_;
    }

    A(const A &other) 
     : A(other.num) {}

    A(A &&other) noexcept 
     : num_(std::exchange(other.num, nullptr)) {}

    A &operator=(const A &other) {
        *num_ = *other.num;
        return *this;
    }

    A &operator=(A &&other) noexcept {
        swap(num_, other.num_);
        return *this;
    };
};

class B {
private:
    std::unique_ptr<int> num_;

public:

    explicit B(int num) : num_(std::make_unique<int>(num)) {};
    ~B() = default;
    B(const B & other) : B(*other.num_) {}
    B(B && other) = default;
    B& operator=(const B & other) { *num_ = *other.num_ }
    B& operator=(B && other) = default;

};