shared_ptr代码实现,当前命名为ushared_ptr。
1、定义模板指针T* ptr_和计数指针int* red_count_.
2、空构造。
3、实例化构造,获取真实类型对象,并且计数new为1.
4、创建引用函数,通过参数获取真实类型对象和计数指针对象,并且计数加一。
5、重载operator=函数,通过参数获取真实类型对象和计数指针对象,并且计数加一。
6、重载 operator*和operator-> 实现指针功能。
7、创建获取真实类型对象的函数。
8、创建获取计数的函数。
9、创建析构函数,计数减一,当计数为0时析构真实类型对象。
代码及测试如下:
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <map>
#include <QDebug>
template <class T>
class ushared_ptr {
private:
// 保存真实指针
T* ptr_;
// 指向引用计数
int* ref_count_;
public:
// 空构造。
ushared_ptr():ref_count_(NULL),ptr_(NULL) {}
// 构造函数
ushared_ptr(T *t) {
ptr_ = t;
// 初始化引用计数
ref_count_ = new int(1);
qWarning()<<"ushared_ptr num"<<*ref_count_;
}
// 引用
ushared_ptr(ushared_ptr& ptr) {
ptr_ = ptr.ptr_;
// 引用计数加1
ref_count_ = ptr.ref_count_;
(*ref_count_)++;
qWarning()<<"ushared_ptr num"<<*ref_count_;
}
// 重载operator=,然后将新的对象引用次数加一。
void operator =(ushared_ptr& ptr) {
ptr_ = ptr.ptr_;
// 引用计数加1
ref_count_ = ptr.ref_count_;
(*ref_count_)++;
qWarning()<<"ushared_ptr num"<<*ref_count_;
}
// 析构
~ushared_ptr()
{
if (ptr_)
{
qWarning()<<"~ushared_ptr num"<<*ref_count_;
if (--(*ref_count_) == 0)
{
qWarning()<<"~ushared_ptr delete"<<*ref_count_;
delete ref_count_;
delete ptr_;
}
else
qWarning()<<"~ushared_ptr delete"<<*ref_count_;
}
}
// 重载 operator*和operator-> 实现指针功能
T operator *() {return *ptr_;}
T* operator ->() {return ptr_;}
// 获取原指针
T* get() {return ptr_;}
// 获取计数
int use_count(){if(ref_count_)return *ref_count_;}
};
class B;
class A
{
public:
ushared_ptr<B> m_b;
A(){}
~A(){qWarning()<<"~A->B num"<<m_b.use_count();}
};
class B
{
public:
ushared_ptr<A> m_a;
B(){}
~B(){qWarning()<<"~B->A num"<<m_a.use_count();}
};
void test()
{
ushared_ptr<A> a(new A);
ushared_ptr<B> b(new B);
qWarning()<<"A num"<<a.use_count();
qWarning()<<"B num"<<b.use_count();
a->m_b = b;
//b->m_a = a;
qWarning()<<"A num"<<a.use_count();
qWarning()<<"B num"<<b.use_count();
}
int main(int argc, char *argv[])
{
test();
}
weak_ptr辅助性智能指针,它的作用就是辅助shared_ptr来使用的,帮助shared_ptr解除多个对象都引用对方指针,造成引用成环的问题,它的原理在于它是一种弱引用,它的各种操作不改变shared_ptr的计数大小的。
如以下例子:
class B;
class A
{
public:
std::shared_ptr<B> m_b;
A(){}
~A(){qWarning()<<"~A->B num"<<m_b.use_count();}
};
class B
{
public:
std::shared_ptr<A> m_a;
B(){}
~B(){qWarning()<<"~B->A num"<<m_a.use_count();}
};
void test()
{
std::shared_ptr<A> a(new A);
std::shared_ptr<B> b(new B);
qWarning()<<"A num"<<a.use_count();
qWarning()<<"B num"<<b.use_count();
a->m_b = b;
b->m_a = a;
qWarning()<<"A num"<<a.use_count();
qWarning()<<"B num"<<b.use_count();
}
int main(int argc, char *argv[])
{
test();
}
结果
A num 1
B num 1
A num 2
B num 2
初始化和赋值后:A的计数为2,B的计数2。a,b跑出作用域后,AB的智能指针进入析构,A的计数减1为1,B的计数减1为1。两边都为1,因此–(*ref_count_) == 0的条件不成立,都无法进入条件语句内部将A和B的对象delete,所以A和B的析构函数都不会进,也就无法继续后面的操作,会出内存泄露。
当使用了weak_ptr后
如以下:
class B;
class A
{
public:
std::shared_ptr<B> m_b;
A(){}
~A(){qWarning()<<"~A->B num"<<m_b.use_count();}
};
class B
{
public:
std::weak_ptr<A> m_a;
B(){}
~B(){qWarning()<<"~B->A num"<<m_a.use_count();}
};
void test()
{
std::shared_ptr<A> a(new A);
std::shared_ptr<B> b(new B);
qWarning()<<"A num"<<a.use_count();
qWarning()<<"B num"<<b.use_count();
a->m_b = b;
b->m_a = a;
qWarning()<<"A num"<<a.use_count();
qWarning()<<"B num"<<b.use_count();
}
int main(int argc, char *argv[])
{
test();
}
结果:
A num 1
B num 1
A num 1
B num 2
~A->B num 1
~B->A num 0
通过结构可以看出,b->m_a = a后A计数仍为1,weak_ptr对shared_ptr的计数不做修改。
初始化和赋值后:A的计数为1,B的计数为2。当a跑出作用域后,A的智能指针进入析构,A的计数减1为0,满足–(*ref_count_) == 0的条件,A会被delete,因此进入A的析构函数,智能指针m_b为A的成员变量,所以它会被析构,然后B的智能指针进入析构函数,B计数减1为1。当b跑出作用域后,B的智能指针进入析构,B的计数减1为0,满足–(*ref_count_) == 0的条件,B会被delete,因此进入B的析构函数,m_a为B的成员变量,它会被析构,此时此刻所有指针都被析构,没有内存泄露。