c++智能指针以及shared_ptr实现

智能指针利用了RAII思想,利用智能指针对象的生命周期控制资源的分配和释放,资源包括堆内存,打开的文件,socket等。

其中shared_ptr使用引用计数的方式,允许多个shared_ptr对象引用资源,每有一个对象引用资源引用计数加一,当引用计数为0时,释放管理的资源。

unique_ptr只允许一个unique_ptr对象引用资源,支支持移动语义,不支持拷贝语义,移动语义下转移资源所有权,使用reset(release())方法。

但是shared_ptr存在循环引用问题。如双向链表的节点,有前驱和后继成员,都是shared_ptr,相邻节点互相引用,造成节点的引用计数最少是2,所引用的资源无法释放而产生泄露。

struct Node
{
	int val;
	shared_ptr<Node> pre;
	shared_ptr<Node> next;
	Node(int v) :val(v){}
};
/*OR
class B;
class A{
	shared_ptr<B> ptr;
};
class B{
	shared_ptr<A> ptr;
};
也可以造成循环引用
*/
int main()
{
	shared_ptr<Node> p1(new Node(1)), p2(new Node(2));
	p1->next = p2;
	p2->pre = p1;
	w1 = p1;
	w2 = p2;
	cout << p1.use_count() << " " << p2.use_count() << endl;//2  2
}

weak_ptr作为shared_ptr的补充,无法直接引用资源,必须靠shared_ptr初始化,不影响引用计数值,不负责资源的释放。所以在资源类中将其中一个成员的类型换成weak_ptr就能打破引用环(不用都换)。

struct Node
{
	int val;
	weak_ptr<Node> pre;
	shared_ptr<Node> next;
	Node(int v) :val(v){}
};
/*OR
class B;
class A{
	weak_ptr<B> ptr;
};
class B{
	shared_ptr<A> ptr;
};
*/

提供share_ptr<T> p = w.lock();方法,当引用计数为0时返回的shared是nullptr,否则指向资源,从而通过shared完成对资源的释放。

weak_ptr<int> w(p);
if(w.use_count() != 0)//不对
{//当多线程操作时,判断完后,另一线程的shared释放了对象,当前线程再操作对象就会出错。
}
if(shared_ptr<int> q = w.lock())//对
{//即使另一线程释放了对象那么得到的q就是空的。
}

简化版

shared_ptr初始化两种方式:

  1. 传指针
int * a = new int(1);
shared_ptr<int> p(a), q(a);//这时两个智能指针对象p,q里的计数无法同步,都是1.
//避免这种
//尽量使用
shared_ptr<int> p(new int(1));
  1. make_shared
shared_ptr<int> p = make_shared<int>(1);
template <typename T>
class shared_ptr
{
private:
	T* data_ptr;
	size_t* count_ptr;

	void minusone()
	{//引用计数减一
		if (--*count_ptr == 0)
		{
			delete data_ptr;
			delete count_ptr;

			data_ptr = count_ptr = nullptr;
		}
	}
public:
	shared_ptr() :data_ptr(nullptr), 
		count_ptr(new size_t(0)) {}
	explicit shared_ptr(T* p): data_ptr(p), 
		count_ptr(new size_t(1)){}
	shared_ptr(const shared_ptr& other) : data_ptr(other.data_ptr),
		count_ptr(&(++*other.count_ptr)) {}
	~shared_ptr()
	{
		minusone();
	}

	shared_ptr& operator=(const shared_ptr& other)
	{
		if (*this == other)
			return *this;
		minusone();
		++*other.count_ptr;

		data_ptr = other.data_ptr;
		count_ptr = other.count_ptr;
		return *this;
	}
	void swap(const shared_ptr& other)
	{
		using std::swap;
		if (*this == other)
			return *this;
		swap(other.count_ptr, count_ptr);
		swap(other.data_ptr, data_ptr);
	}

	void reset(T* p)
	{
		minusone();
		data_ptr = p;
		*count_ptr = 1;
	}
	T* release()
	{
		minusone();
		return data_ptr;
	}
};

添加删除函数

template <typename T>
class shared_ptr
{
	typedef void(*DelFuncPtr)(T*);

private:
	T* data_ptr;
	size_t* count_ptr;
	DelFuncPtr del;

	void minusone()
	{
		if (--*count_ptr == 0)
		{
			del(data_ptr);
			delete count_ptr;

			data_ptr = nullptr;
			count_ptr = nullptr;
		}
	}
public:
	shared_ptr() :data_ptr(nullptr), count_ptr(new size_t(0)),
		del(nullptr) {}
	explicit shared_ptr(T* p, DelFuncPtr d = nullptr) : data_ptr(p), 
		count_ptr(new size_t(1)), del(d){}
	shared_ptr(const shared_ptr& other) : data_ptr(other.data_ptr),
		count_ptr(&(++*other.count_ptr)), del(other.del) {}
	~shared_ptr()
	{
		del(data_ptr);
		delete count_ptr;
	}

	shared_ptr& operator= (const shared_ptr& other)
	{
		if (other == *this)
			return *this;
		minusone();

		++*other.count_ptr;//拷贝构造和赋值运算,一定不要忘了两个对象的引用计数都要加1.

		data_ptr = other.data_ptr;
		count_ptr = other.count_ptr;
		del = other.del;
		return *this;
	}

	void swap(shared_ptr& other)
	{
		swap(other.data_ptr, data_ptr);
		swap(other.count_ptr, count_ptr);
		swap(other.del, del);
	}

	void reset(T* p, DelFuncPtr d=nullptr)
	{
		//丢弃原本指向的对象,转而指向新的对象。
		minusone();
		data_ptr = p;
		count_ptr = 1;
		del = d;
	}

	T* release()
	{
		minusone();
		return data_ptr;
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值