C++ 简单实现shared_ptr

本文深入探讨了C++中的智能指针shared_ptr,它管理内存,实现自动垃圾回收,并允许对象所有权的共享。shared_ptr通过引用计数机制确保在最后一个拥有者释放后正确删除对象。它支持复制和赋值操作,但不支持指针算术。此外,介绍了shared_ptr的构造、析构、赋值、重置等成员函数,以及make_shared等实用函数,强调了安全性和资源管理的重要性。
摘要由CSDN通过智能技术生成

共享指针

管理指针的存储,提供有限的垃圾回收工具,并可能与其他对象共享该管理。

shared_ptr类型的对象都能够获得指针的所有权并共享该所有权:一旦它们获得所有权,当最后一个所有者释放该所有权时,指针的所有者组就负责删除该所有者。

shared_ptr对象在自身被销毁后,或者一旦其值因赋值操作或显式调用 shared_ptr::reset 而发生更改,就会释放其共同拥有的对象的所有权。一旦通过指针共享所有权的所有shared_ptr对象都释放了此所有权,则将删除托管对象(通常通过调用 ::delete,但在构造时可能会指定不同的删除程序)。

shared_ptr对象只能通过复制其值来共享所有权:如果从同一个(非shared_ptr)指针构造(或创建)两个shared_ptr,则它们都将拥有该指针而不共享它,当其中一个对象释放它(删除其托管对象)并使另一个指向无效位置时,会导致潜在的访问问题。

此外,shared_ptr对象可以通过指针共享所有权,同时指向另一个对象。此功能称为别名,通常用于指向成员对象,同时拥有它们所属的对象。因此,shared_ptr可能与两个指针相关:

  • 存储的指针,它是它所指向的指针,也是它使用运算符* 取消引用的指针。
  • 拥有的指针(可能是共享的),这是所有权组负责在某个时刻删除的指针,并且它被视为一种用途。

通常,存储的指针和拥有的指针引用同一对象,但别名shared_ptr对象(使用别名构造函数及其副本构造的对象)可能引用不同的对象。

不拥有任何指针的shared_ptr称为空shared_ptr。不指向任何对象的shared_ptr称为 null shared_ptr,不应取消引用。请注意,空shared_ptr不一定是 null shared_ptr,null shared_ptr不一定是空shared_ptr。

shared_ptr对象通过运算符 * 和 -> 提供对它们所指向的对象的访问,从而复制有限的指针功能。出于安全原因,它们不支持指针算术。

相关类weak_ptr能够与shared_ptr对象共享指针,而无需拥有它们。

成员函数

	(构造函数)构造shared_ptr(公共成员函数)
	(析构函数)销毁shared_ptr(公共成员函数)
	operator=	shared_ptr赋值(公共成员函数)
	swap	交换内容(公共成员函数)
	reset	重置指针(公共成员函数)
	get	获取指针(公共成员函数)
	operator*	取消引用对象(公共成员函数)
	operator->	取消引用对象成员(公共成员函数)
	operator[]  (C++17)提供到被存储数组的带下标访问(公开成员函数)
	use_count	返回计数(公共成员函数)
	unique(C++20前)	检查是否唯一(公共成员函数)
	operator bool	检查是否不为空(公共成员函数)
	owner_before	基于所有者的共享指针排序(公共成员函数模板)

非成员函数
	swap	交换shared_ptr对象的内容(函数模板)
	relational operators	关系运算符 ==, !=, <, <=, >, >= (函数模板 )
	ostream operator<<	将存储的指针的值输出到输出流(函数模板)

具体功能:
	make_shared,make_shared_for_overwrite(C++20)	创建管理一个新对象的共享指针(函数模板)
	allocate_shared,allocate_shared_for_overwrite(C++20)	创建管理一个用分配器分配的新对象的共享指针(函数模板)
	static_pointer_cast,dynamic_pointer_cast,const_pointer_cast,reinterpret_pointer_cast    (C++17)应用 static_cast、dynamic_cast、const_cast 或 reinterpret_cast 到被存储指针(函数模板)
	get_deleter	返回指定类型中的删除器,若其拥有(函数模板)

cpp

#include <utility>
#include <cstddef>

class ref_count
{
public:
    int use_count() const noexcept { return count_; }
    void inc_ref() noexcept { ++count_; }
    int dec_ref() noexcept { return --count_; }

private:
    int count_{1};
};

template <typename T>
class Shared_ptr
{
public:
    constexpr Shared_ptr() noexcept = default;
    constexpr Shared_ptr(nullptr_t) noexcept : Shared_ptr() {}
    explicit Shared_ptr(T *ptr) : ptr_{ptr}
    {
        if (ptr_ != nullptr)
        {
            rep_ = new ref_count{};
        }
    }
    Shared_ptr(const Shared_ptr &rhs) noexcept : ptr_{rhs.ptr_}, rep_{rhs.rep_}
    {
        if (ptr_ != nullptr)
        {
            rep_->inc_ref();
        }
    }
    Shared_ptr(Shared_ptr &&rhs) noexcept : ptr_{rhs.ptr_}, rep_{rhs.rep_}
    {
        rhs.ptr_ = nullptr;
        rhs.rep_ = nullptr;
    }
    ~Shared_ptr() noexcept
    {
        if (rep_ != nullptr && rep_->dec_ref() == 0)
        {
            delete ptr_;
            delete rep_;
        }
    }

    Shared_ptr &operator=(const Shared_ptr &rhs)
    {
        Shared_ptr{rhs}.swap(*this);
        return *this;
    }
    Shared_ptr &operator=(Shared_ptr &&rhs)
    {
        Shared_ptr{std::move(rhs)}.swap(*this);
        return *this;
    }
    void reset() noexcept
    {
        Shared_ptr{}.swap(*this);
    }
    void reset(nullptr_t) noexcept
    {
        reset();
    }
    void reset(T *ptr)
    {
        Shared_ptr{ptr}.swap(*this);
    }

    void swap(Shared_ptr &rhs) noexcept
    {
        std::swap(ptr_, rhs.ptr_);
        std::swap(rep_, rhs.rep_);
    }
    T *get() const noexcept
    {
        return ptr_;
    }

    long use_count() const noexcept
    {
        return rep_ == nullptr ? 0 : rep_->use_count();
    }
    bool unique() const noexcept
    {
        return rep_->use_count() == 1;
    }

    T &operator*() const noexcept
    {
        return *ptr_;
    }
    T &operator->() const noexcept
    {
        return ptr_;
    }

    explicit operator bool() const noexcept
    {
        return static_cast<bool>(ptr_);
    }

private:
    T *ptr_{nullptr};
    ref_count *rep_{nullptr};
};

template <typename T, typename... Args>
auto make_Shared(Args &&...args)
{
    return Shared_ptr<T>{new T(std::forward(args)...)};
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
shared_ptrC++中用于动态内存管理的智能指针之一。它能够记录对象被引用的次数,主要用于管理动态创建的对象的销毁。使用shared_ptr可以避免内存泄漏和悬挂指针等问题。 在C++中,实现shared_ptr通常需要以下几个步骤: 1. 定义一个模板类,例如SHARED_ptr,该类将作为智能指针使用。 2. 在SHARED_ptr类中,定义一个指针成员变量ptr,用于指向实际的对象。 3. 在SHARED_ptr类中,定义一个计数器类的指针成员变量refcount,用于记录对象被引用的次数。 4. 在SHARED_ptr类中,实现构造函数,用于初始化指针和计数器。 5. 在SHARED_ptr类中,实现拷贝构造函数和赋值操作符重载,用于处理多个智能指针共享同一对象的情况。 6. 在SHARED_ptr类中,实现析构函数,用于释放对象的内存空间。 7. 在SHARED_ptr类中,实现箭头运算符重载和解引用运算符重载,用于访问对象的成员函数和数据。 8. 在SHARED_ptr类外部,实现计数器类RefCount,用于记录对象被引用的次数,并在引用次数为0时释放对象的内存空间。 实现shared_ptr的详细代码如下所示: ```cpp template <class T> class SHARED_ptr { private: T* ptr; // 用来指向堆区对象 RefCount<T>* refcount; // 指向计数器对象的指针 public: SHARED_ptr(T* p) : ptr(p), refcount(new RefCount<T>()) { refcount->increment(); } SHARED_ptr(const SHARED_ptr<T>& other) : ptr(other.ptr), refcount(other.refcount) { refcount->increment(); } ~SHARED_ptr() { if (refcount->decrement() == 0) { delete ptr; delete refcount; } } T* operator->() const { return ptr; } T& operator*() const { return *ptr; } SHARED_ptr& operator=(const SHARED_ptr<T>& other) { if (this != &other) { if (refcount->decrement() == 0) { delete ptr; delete refcount; } ptr = other.ptr; refcount = other.refcount; refcount->increment(); } return *this; } }; ``` 以上是一个简单C++实现shared_ptr的示例代码。通过使用shared_ptr,我们可以方便地管理动态创建的对象的生命周期,并避免内存泄漏和悬挂指针等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃米饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值