shared_ptr能和基于引用计数的智能指针混用吗?

简介: shared_ptr能和基于引用计数的智能指针混用吗?

前言

我在上一篇文章中介绍了几种误用智能指针的例子。还有一种比较典型,就是混用两种类型的智能指针。直接看代码吧!

示例代码

#include "stdafx.h"
#include <memory>
#include <iostream>
#include "RefCountedPtr.h"

class PBObject : public RefCounted<IRefCounted>
{
public:
    virtual double Volume() { return 0.0; }
};

class PBWall : public PBObject
{
public:
    virtual double Volume() { return 100.0; }

    ~PBWall() { std::cout << __FUNCTION__ << std::endl; }
};

void Test()
{
    RefCountedPtr<PBObject> pWall(new PBWall());
    std::shared_ptr<PBObject> pSharedWall(pWall.get());
}

int _tmain(int argc, _TCHAR* argv[])
{
    Test();
    return 0;
}

pWall 在析构的时候会调用 Release() 递减引用计数到 0,从而调用 deletepSharedWall 拿着同样的指针,在析构的时候也会调用 delete 删除同一块地址。于是暴雷了!

那么有办法把 RefCountPtr 类型的智能指针交给 shared_ptr 管理吗?答案是肯定的,只需要把 Test() 改成看下面这样即可:

void Test()
{
    RefCountedPtr<PBObject> pWall(new PBWall());
    std::shared_ptr<PBObject> pSharedWall(pWall.get(), 
        [](PBObject* p){ /* p->Release(); */ } // use customized deleter, do nothing, can't call p->Release();
    );
}

在构造 shared_ptr 类型的智能指针的时候,可以传递一个自定义的 Deleter,这个 Deleter 不需要做任何事情。

基于引用计数的智能指针的一个实现

基于引用计数的智能指针常用于 COM 编程中,下面的代码是一份简要的实现,感兴趣的小伙伴儿可以看一看。毕竟,手机不太适合看代码,也可以下载后在电脑上查看。

#include "stdafx.h"
#include <memory>
#include <iostream>

// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template <class Base> class RefCounted : public Base
{
protected:
    virtual ~RefCounted() {}

public:
    RefCounted() { m_refCount = 0; }
    RefCounted(RefCounted const& rhs) { m_refCount = 0; }
    RefCounted& operator=(RefCounted const& rhs) { if (this != &rhs) { Base::operator=(rhs); } return *this; }
    int GetRefCount() const { return m_refCount; }
    int AddRef() const { return ++m_refCount; }
    int Release() const
    {
        int refCount = --m_refCount;
        if (0 < refCount)
        {
            return refCount;
        }

        delete this;
        return 0;
    }

private:
    mutable int m_refCount;
};

class IRefCounted
{
protected:
    virtual ~IRefCounted() {}

public:
    virtual int AddRef() const = 0;
    virtual int Release() const = 0;
};

template<class T> class RefCountedPtr
{
private:

    typedef RefCountedPtr this_type;

public:

    RefCountedPtr() : p_(0) {}

    RefCountedPtr(T * p, bool add_ref = true) : p_(p)
    {
        if (p_ != 0 && add_ref) p_->AddRef();
    }

    template<class U> RefCountedPtr(RefCountedPtr<U> const & rhs) : p_(rhs.get())
    {
        if (p_ != 0) p_->AddRef();
    }

    RefCountedPtr(RefCountedPtr const & rhs) : p_(rhs.p_)
    {
        if (p_ != 0) p_->AddRef();
    }

    ~RefCountedPtr()
    {
        if (p_ != 0) p_->Release();
    }

    template<class U> RefCountedPtr & operator=(RefCountedPtr<U> const & rhs)
    {
        this_type(rhs).swap(*this);
        return *this;
    }

    bool operator== (RefCountedPtr<T> const& rhs) const
    {
        return p_ == rhs.p_;
    }

    template<class U> bool operator== (RefCountedPtr<U> const& rhs) const
    {
        return p_ == rhs.get();
    }

    bool operator!= (RefCountedPtr<T> const& rhs) const
    {
        return p_ != rhs.p_;
    }

    template<class U> bool operator!= (RefCountedPtr<U> const& rhs) const
    {
        return p_ != rhs.get();
    }

    RefCountedPtr & operator=(RefCountedPtr const & rhs)
    {
        this_type(rhs).swap(*this);
        return *this;
    }

    RefCountedPtr & operator=(T * rhs)
    {
        this_type(rhs).swap(*this);
        return *this;
    }

    T * get() const
    {
        return p_;
    }

    T& operator*() const
    {
        return *p_;
    }

    T * operator->() const
    {
        return p_;
    }

    void swap(RefCountedPtr & rhs)
    {
        T * tmp = p_;
        p_ = rhs.p_;
        rhs.p_ = tmp;
    }

private:

    T * p_;
};

附件

文中的 RefCounterPtr 实现可以参考附件,下载地址如下:

百度云盘链接: https://pan.baidu.com/s/1HpFELQf97pkximT5oGm2pg 提取码: h7w8

CSDN:https://download.csdn.net/download/xiaoyanilw/13679955

总结

shared_ptrDeleter 妙用无穷,本文只是其中的一个用处。

相关文章
|
6月前
|
安全 程序员 编译器
C++中的RAII(资源获取即初始化)与智能指针
C++中的RAII(资源获取即初始化)与智能指针
82 0
|
6月前
|
安全 程序员 C++
C++中的智能指针:从原始指针到现代内存管理
C++中的智能指针:从原始指针到现代内存管理
49 0
|
6月前
|
C++
C++:一文读懂智能指针
C++:一文读懂智能指针
99 0
|
6月前
|
安全 C++ 容器
C++中的智能指针:自动内存管理的利器
C++中的智能指针:自动内存管理的利器
83 0
|
6月前
|
存储 Rust C++
C++智能指针
【2月更文挑战第14天】介绍C++智能指针
49 0
|
6月前
|
算法 安全 C++
C++ Effective Modern Pointer (智能指针模块)
C++ Effective Modern Pointer (智能指针模块)
|
6月前
|
安全 C++
C++智能指针的用法
C++智能指针的用法
59 0
|
6月前
|
存储 安全 程序员
c++11智能指针的基本使用
程序员自己管理堆内存可以提高程序的效率,但是管理比较麻烦,使用普通指针,容易造成堆内存泄漏(忘记释放),二次释放问题。
60 0
|
6月前
|
安全 编译器 C++
智能指针shared_ptr、unique_ptr、weak_ptr
智能指针shared_ptr、unique_ptr、weak_ptr
175 0
|
6月前
|
C++
C++智能指针weak_ptr
C++智能指针weak_ptr
33 0