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

前言

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

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#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() 改成看下面这样即可:

1
2
3
4
5
6
7
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 编程中,下面的代码是一份简要的实现,感兴趣的小伙伴儿可以看一看。毕竟,手机不太适合看代码,也可以下载后在电脑上查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#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 妙用无穷,本文只是其中的一个用处。

BianChengNan wechat
扫描左侧二维码关注公众号,扫描右侧二维码加我个人微信:)
0%