c++ 之 shared_ptr

/*
 * shared_ptr
 */
    shared_ptr 是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个 shared_ptrs 共同指向一个对象。
    这便是所谓的引用计数(reference counting)。

    一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。
    这在非环形数据结构中防止资源泄露很有帮助。


    类似 vector 智能指针也是模板。

        shared_ptr<string> p1;        // shared_ptr,可以指向string
        shared_ptr<list<int>> p2;   // shared_ptr,可以指向int的list

    智能指针的使用方法和普通指针类似,解引用返回它指向的对象,如果在一个条件判断中使用智能指针,效果就是检测它是否为空,

        // 如果 p1 不为空,检查它是否指向一个空 string
        if (p1 && p1->empty()) // p->mem -- (*p).mem
            *p1 = "ds"

/*
 * share_ptr 的拷贝和赋值
 */
    当进行拷贝或赋值操作时,每个 shared_ptr 都会记录有多少个其他 shared_ptr 指向相同的对象:

        auto p = make_shared<int>(42);        // p指向的对象只有p一个引用者
        auto q(p);                            // p和q指向相同对象,此对象有两个引用者

    可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)。
        
        无论何时拷贝一个shared_ptr,计数器都会递增;
        当给shared_ptr赋予一个新值或是shared_ptr被销毁时,计算器就会递减。
        
        一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象:

            auto r = make_shared<int>(42);    // r指向的int只有一个引用者
            r = q;    // 给r赋值,令它指向另一个地址
                      // 递增q指向的对象的引用计数
                      // 递减r原来指向对象的引用计数
                      // r原来指向的对象已没有引用者,会自动释放

 /*
  * share_ptr 自动销毁所管理的对象
  */
    当指向一个对象最后一个 share_ptr 被销毁时,share_ptr 类会自动销毁此对象。
    它是通过另一个特殊的成员函数——析构函数完成销毁工作的。

/*
 * shared_ptr 和 new 结合使用
 */
    可以使用 new 返回的指针来初始化智能指针,智能指针是一个类,分装了一个原始的 C++ 指针,用以管理所指对象的生命期。

    shared_ptr<double> p1;                // shared_ptr可以指向一个double
    shared_ptr<int> p2(new int (42));   // p2指向一个值为42的int

    接受指针参数的智能指针构造函数是 explicit 的。
    因此,我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式来初始化一个智能指针:

    shared_ptr<int> p1 = new int(1024);    //错误:必须使用直接初始化形式
    shared_ptr<int> p2(new int (1024));    //正确:使用了直接初始化

    出于相同的原因,一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针:

        shared_ptr<int> clone(int p) {
            return new int(p);                    //错误:隐式转换为shared_ptr<int>
        }

        shared_ptr<int> clone(int p) {
            return shared_ptr<int>(new int(p)); //正确:显式地用int*创建shared_ptr<int>
        }

    默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象。
    可以将智能指针绑定到一个指向其他类型的资源的指针上,但是为了这样做,必须提供操作来代替  delete 。

/*
 * weak_ptr
 */
    weak_ptr是为配合shared_ptr而引入的一种智能指针。

    weak_ptr可以从一个shared_ptr或另一个weak_ptr对象构造,
    它的构造和析构不会引起shared_ptr引用记数的增加或减少(但会导致引用计数区域内负责weak_ptr计数变量_M_weak_count的增加或减少,
    当其计数为0时,调用_M_destroy()释放对象内存)。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象。

    weak_ptr的一个重要用途是通过lock获得this指针的shared_ptr,使对象自己能够生产shared_ptr来管理自己,
    但助手类enable_shared_from_this的shared_from_this会返回this的shared_ptr,只需要让想被shared_ptr管理的类从它继承即可。


/*
 * example
 */
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
 
struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // 注意:此处非虚析构函数 OK
    ~Base() { std::cout << "  Base::~Base()\n"; }
};
 
struct Derived: public Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }
};
 
void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // 线程安全,虽然自增共享的 use_count
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}
 
int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();
 
    std::cout << "Created a shared Derived (as a pointer to Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    p.reset(); // 从 main 释放所有权
    std::cout << "Shared ownership between 3 threads and released\n"
              << "ownership from main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.join(); t2.join(); t3.join();
    std::cout << "All threads completed, the last one deleted Derived\n";
}

#if 0
  Base::Base()
  Derived::Derived()
Created a shared Derived (as a pointer to Base)
  p.get() = 0x56072b522260, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
  p.get() = 0, p.use_count() = 0
local pointer in a thread:
  lp.get() = 0x56072b522260, lp.use_count() = 6
local pointer in a thread:
  lp.get() = 0x56072b522260, lp.use_count() = 4
local pointer in a thread:
  lp.get() = 0x56072b522260, lp.use_count() = 2
  Derived::~Derived()
  Base::~Base()
All threads completed, the last one deleted Derived
#endif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值