文章目录
- 1. 简述
- 2. 简单实现
- 2.1 整形的智能指针
- 2.2 二叉树节点类型的智能指针
- 2.3 通用指针类型
- 2.4 unique_ptr
- 2.5 引用计数 shared_ptr
- 3. 存在问题
- 4. Ref
1. 简述
智能指针即使用跟普通指针一样,
但是拥有自动回收内存的能力。
2. 简单实现
利用C++中的局部对象的构造析构特性,实现RAII。
2.1 整形的智能指针
简单的int类型的智能指针实现
class smp
{
public:explicit smp(int *q = nullptr):p(q){}~smp(){delete p;}
private:int *p;
};
// ... smp sp(new int(10));*sp = 5;std::cout << *sp << std::endl;
2.2 二叉树节点类型的智能指针
还需要重载->
符号,访问数据中的其他成员。
struct node {explicit node(int v = 3):left(nullptr),right(nullptr){}struct node *left;struct node *right;int value;
};
class node_smp {
public:explicit node_smp(node *q = nullptr):p(q){}~node_smp(){delete p;}node& operator*(){ return *p;}node* operator->(){ return p;}
public:node *p;
};node_smp nsmp(new node(10));nsmp->value = 20;std::cout << nsmp->value << std::endl;
2.3 通用指针类型
template<typename T>
class smart_ptr {
public:explicit smart_ptr(T *p = nullptr):q(p){}~smart_ptr(){delete q;q = nullptr;}T& operator *(){ return *q;}T* operator->(){return q;}private:T *q;
};smart_ptr<node> smp(new node(10));smp->value = 100;std::cout << smp->value << std::endl;
2.4 unique_ptr
在上面代码的基础上禁止资源的转移,就是unique_ptr
的雏形啦。
template<typename T>
class unique_ptr_ {
public:explicit unique_ptr_(T *p = nullptr):ptr(p){}~unique_ptr_(){delete ptr;}unique_ptr_(const unique_ptr_& p) = delete;unique_ptr_& operator=(const unique_ptr_& p) = delete;
private:T *ptr;
};
2.5 引用计数 shared_ptr
到目前为止,实际上我们并没有处理拷贝构造函数和赋值函数。
在一个返回内的智能指针,且不会在别的地方被引用。
也就是该智能指针无法在另外一个地方再使用。
那么怎么实现能使用多个智能指针对象呢,标准库实现的方式是引用计数。
而要对多个对象进行计数,且多个对象的销毁并不确定,所以只能在对象首次使用时使用在堆上的分配一个内存进行引用计数。
当最后一个只能对象销毁时,销毁资源。
template<typename T>
class shared_ptr_ {
public:explicit shared_ptr_(T *data = nullptr):RefCnt(new int {0}) {data_ = data;*RefCnt = 0;if (data_) {++*RefCnt;}}~shared_ptr_() {--*RefCnt;if (*RefCnt == 0) {delete data_;delete RefCnt;}}shared_ptr_& operator=(const shared_ptr_ & p) {if ( *this != p) {RefCnt = p.RefCnt;data_ = p.data_;++*RefCnt;}return *this;}shared_ptr_(const shared_ptr_ &p) {data_ = p.data_;RefCnt = p.RefCnt;++*RefCnt;}T& operator*(){return *data_;}T* operator->(){return data_;}
private:T *data_;int *RefCnt;
};
在使用循环链表的过程中即存在这种情况:
template<typename T>
class shared_ptr_ {
public:explicit shared_ptr_(T *data = nullptr):data_(data),RefCnt(new int {0}){if (data_) {++*RefCnt;}}~shared_ptr_() {if (*RefCnt) {--*RefCnt;if ( *RefCnt )std::cout << "current ref: "<< *RefCnt << std::endl;}if (*RefCnt == 0) {delete data_;delete RefCnt;}}shared_ptr_<T>& operator=(const shared_ptr_<T> & p) {if ( this != &p) {RefCnt = p.RefCnt;data_ = p.data_;if (*RefCnt) {++*RefCnt;}}return *this;}shared_ptr_(const shared_ptr_ &p) {data_ = p.data_;RefCnt = p.RefCnt;if (*RefCnt)++*RefCnt;}T& operator*(){return *data_;}T* operator->(){return data_;}
private:T *data_;int *RefCnt;
};class List {
public:explicit List(int _v = 0):v(_v), pPre(), pNext(){}~List(){std::cout << "delete List " << v << std::endl;}int v;shared_ptr_<List> pPre;shared_ptr_<List> pNext;
};int main()
{shared_ptr_<List> p1(new List(2));shared_ptr_<List> p2(new List(3));p1->pPre = p2;p2->pPre = p1;p1->pNext = p2;p2->pNext = p1;return 0;
}
输出
current ref: 2
current ref: 2
由于实际上在链表中,并不实际占有资源而只是一个引用。所以会出现程序运行后还剩两个计数。
即对于p1
,还有p1->pPre
和p1->next
两个指针计数。
3. 存在问题
更好的实现就要看boost
和标准库这些的相关实现了。
- 循环引用未解决
- 线程安全问题
- 异常安全
- 继承
4. Ref
code_review
csdn
code_project