上一篇:C++技能点之智能指针(一)
五、如何实现一套简单的智能指针
- 先来看一段代码,来自C++ 智能指针:原理与实现[1]
// SmartPointer.h
#include <iostream>
using namespace std;
template<class T>
class SmartPointer
{
public:
SmartPointer();
SmartPointer(T* target);
SmartPointer(const SmartPointer<T>& from);
~SmartPointer();
static T* New();
bool operator == (const SmartPointer<T>& other) const;
bool operator != (const SmartPointer<T>& other) const;
SmartPointer<T>& operator = (const SmartPointer<T>& that);
T& operator*() const;
T* operator->() const;
int getRefCount();
protected:
void addReference();
void removeReference();
private:
T* m_Pointer; // 指向资源的指针
int* m_RefPointer; // 指向引用计数的指针
};
template<typename T>
SmartPointer<T>::SmartPointer()
: m_Pointer(nullptr), m_RefPointer(nullptr){}
template<typename T>
SmartPointer<T>::SmartPointer(T* target)
: m_RefPointer(nullptr), m_Pointer(target)
{
addReference();
}
template<typename T>
SmartPointer<T>::SmartPointer(const SmartPointer<T>& from)
: m_RefPointer(from.m_RefPointer), m_Pointer(from.m_Pointer)
{
addReference();
}
template<typename T>
T* SmartPointer<T>::New()
{
return new T();
}
template<typename T>
SmartPointer<T>::~SmartPointer()
{
removeReference();
}
template<typename T>
void SmartPointer<T>::addReference()
{
if(m_RefPointer)
(*m_RefPointer)++;
else
m_RefPointer = new int(1);
}
template<typename T>
void SmartPointer<T>::removeReference()
{
if(m_RefPointer){
(*m_RefPointer)--;
if(*m_RefPointer == 0)
{
delete m_RefPointer;
delete m_Pointer;
m_RefPointer = nullptr;
m_Pointer = nullptr;
}
}
}
template<typename T>
bool SmartPointer<T>::operator == (const SmartPointer<T>& other) const
{
return m_Pointer == other.m_Pointer;
}
template<typename T>
bool SmartPointer<T>::operator != (const SmartPointer<T>& other) const
{
return !operator==(other);
}
template<typename T>
SmartPointer<T>& SmartPointer<T>::operator = (const SmartPointer<T>& that)
{
if(this != &that)
{
removeReference();
this->m_Pointer = that.m_Pointer;
this->m_RefPointer = that.m_RefPointer;
addReference();
}
return *this;
}
template<typename T>
T& SmartPointer<T>::operator*() const
{
return *m_Pointer;
}
template<typename T>
T* SmartPointer<T>::operator->() const
{
return m_Pointer;
}
template<typename T>
int SmartPointer<T>::getRefCount()
{
if(m_RefPointer)
return *m_RefPointer;
return -1;
}
- 先来分析一下这段代码,这一段实现了智能指针的基本功能。包含了默认的构造函数,裸指针构造,拷贝构造,析构函数;添加了静态
New()
方法,重载了几种常见的运算符(判断是否相等和不相等,赋值,解引用和访问成员函数运算符),当然还有引用计数的部分(增加,减少,取值)。由于智能指针需要对所有数据类型适用,最好的实现方式就是采用模板类的方式。- 首先由于每块资源都要有一个引用计数,所以要有一个指向引用计数的指针,用来管理指向这块资源的指针数。
- 对于引用计数,
addReference()
即增加引用计数,如果引用计数的指针为空就new
一个新的,如果不为空就加1。removeReference()
同理,如果引用计数指针不为空就减1,如果减到0就delete掉指向资源的指针及引用计数的指针。- 对于构造函数,默认构造函数不指向资源,所以指针均为空;裸指针构造,有指向资源的指针,但引用计数并不记录所有指针的个数,而是只记录智能指针的个数,所以引用计数指针为空并初始化引用计数;拷贝构造就将另一个智能指针的指向和引用计数均记录下来;而静态的
New()
方法是为了统一用法封装了一层。- 接下来用一段代码测试一下,来自C++ 智能指针:原理与实现 [1]
#include <iostream>
#include "SmartPointer.h"
using namespace std;
class A
{
public:
A() { cout << "constuct = " << this << endl; };
~A() { cout << "destruct = " << this << endl; };
void Print()
{
cout << "print() = " << this << endl;
}
};
int main()
{
SmartPointer<A> sp_outer;
{
cout << "start " << endl;
SmartPointer<A> sp_1 = SmartPointer<A>::New();
cout << "create smart pointer, refCount = " << sp_1.getRefCount() << endl;
SmartPointer<A> sp_2 = sp_1;
cout << "object construct, refCount = " << sp_2.getRefCount() << endl;
sp_1 = SmartPointer<A>::New();
cout << "origin refCount = " << sp_2.getRefCount()
<< ", current refCount = " << sp_1.getRefCount() << endl;
sp_1->Print();
sp_outer = sp_1;
cout << "end" << endl;
}
cout << "finish" << endl;
}
- 这段代码很简单,就是为了测试一下我们的智能指针是否能得到正确的结果。结果如下:
start
constuct = 0x100100360
create smart pointer, refCount = 1
object construct, refCount = 2
constuct = 0x100100630
origin refCount = 1, current refCount = 1
print() = 0x100100630
end
destruct = 0x100100360
finish
destruct = 0x100100630
- 这段结果中唯一要解释一下的是当
sp_1
再次调用静态New()
方法时,相当于重新构建智能指针,此时指向之前资源的引用计数会减1,所以导致origin refCount = 1
。其余的输出结果符合预期,如有不懂的可以参照前篇 上一篇:C++技能点之智能指针(一)- 多说一点,其实这段代码中还可以继续完善,比如可以考虑把引用计数再进行封装,需要注意引用计数的原子性,感兴趣的朋友可以进一步更改参照
std::shared_ptr
。
参考
[1] C++ 智能指针:原理与实现【这篇写的很好】