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

Posted

技术标签:

【中文标题】智能指针如何影响 5 规则?【英文标题】:How do smart pointers affect the rule of 5? 【发布时间】:2020-04-15 07:57:19 【问题描述】:

我了解到,当您在类中使用指针时,您应该实现规则 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)) ;

;

【问题讨论】:

请注意,示例不会做同样的事情,因为第二个示例将隐式删除复制构造函数和赋值运算符,因为std::unique_ptr 不可复制 啊,这很有道理。那么我应该使用std::shared_ptr吗? 这取决于您是否希望 B 可复制(AB 都是可移动的) @CiaranWelsh 这不应该是您选择智能指针类型的理由。而是:您是否需要共享所有权。在A 中没有共享所有权(至少不正确;) 我想这是一个错字:if (this == &amp;other) 【参考方案1】:

是的,这就足够了。唯一指针确实管理内存。但是,您的两个类的行为会有所不同,因为无法复制 std::unique_ptr,因此不会有编译器生成的复制构造函数,也不会为 B 赋值。

还请注意,您实现了规则 5 的所有方法,但不正确。如评论中所述,复制 A 将导致两个实例具有相同的指针并在销毁时将其删除。实际上,正确理解这一点就是关于 3/5 规则的全部意义,以及为什么你应该更喜欢 0 规则。

【讨论】:

【参考方案2】:

如果您使用智能指针(或任何 std:: 容器),类默认析构函数将调用智能指针(和容器)的析构函数。 有关此主题的更多信息:Why doesn't the C++ default destructor destroy my objects?

【讨论】:

【参考方案3】:

那些有不同的行为。 A 可以复制,B 只能移动。

注意你对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)) ;

;

或者定义B的副本

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;

;

【讨论】:

以上是关于智能指针如何影响 5 规则?的主要内容,如果未能解决你的问题,请参考以下文章

[C++] 智能指针

[C++] 智能指针

[C++] 智能指针

[C++] 智能指针

如何防止智能指针循环引用问题

C++异常机制和智能指针机制的杂谈