C++复习笔记24

1.scoped_array以及unique_ptr unique_ptr的实现原理:简单粗暴的防拷贝

#include<iostream>
#include<boost/smart_ptr.hpp>
using namespace std;
using namespace boost;

void test01()
{
	int* ptr = new int[10]{ 1,2,3,4,5,6,7,8,9,10 };
	scoped_array<int> sa(ptr);

	for (int i = 0; i < 10; ++i)
		cout << sa[i] << " ";
	cout << endl;
}

void test02()
{
	int* ptr = new int(10);
	unique_ptr<int> up(ptr);
    cout << *up << endl;
	//unique_ptr<int> up1 = up;//不能赋值也不能拷贝构造
}

void main()
{
	test02();
}

2.shared_ptr:所有权共享,使用引用计数,减到零才释放空间

#include<iostream>
#include<boost/smart_ptr.hpp>
//#include<boost/shared_ptr.hpp>
using namespace std;
//using namespace boost;

void test01()
{
	int* ptr = new int(10);
	shared_ptr<int> sp(ptr);
	cout << *sp << endl;
	cout << "use count" << sp.use_count() << endl;
	{
		shared_ptr<int> sp1;
		sp1 = sp;
		cout << "use count" << sp1.use_count() << endl;
	}
	shared_ptr<int> sp2 = sp;
	cout << "use count" << sp2.use_count() << endl;
}

void main()
{
	test01();
}

3.shared_ptr模拟实现

shared_ptr 的原理:是通过引用计数的方式来实现多个 shared_ptr 对象之间共享资源
1. shared_ptr 在其内部, 给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享
2. 对象被销毁时 ( 也就是析构函数调用 ) ,就说明自己不使用该资源了,对象的引用计数减一。
3. 如果引用计数是 0 ,就说明自己是最后一个使用该资源的对象, 必须释放该资源
4. 如果不是 0 ,就说明除了自己还有其他对象在使用该份资源, 不能释放该资源 ,否则其他对象就成野指
针了。

shared_count.h

#pragma once
#include"sysutil.h"
#include"sp_counted_base.h"
#include"sp_counted_impl.h"
template<class Type>
class shared_count
{
public:
	template<class Y >
	shared_count(Y*  p):pi_(new sp_counted_impl<Y>(p))
	{
#ifdef DISPLAY
		std::cout << "Create SHARED_COUNT" << std::endl;
#endif
	}

	shared_count(const shared_count<Type>& r) :pi_(r.pi_)
	{
		if (pi_)
			pi_->add_ref_copy();
	}

	void swap(shared_count& r)
	{
		sp_counted_base* tmp = r.pi_;
		r.pi_ = pi_;
		pi_ = tmp;
	}

	~shared_count()
	{
#ifdef DISPLAY
		std::cout << "Free SHARED_COUNT" << std::endl;
#endif
		if (pi_ != NULL)
		{
			pi_->release();
		}
	}

	long use_count()const
	{
		return pi_->use_count();
	}

private:
	sp_counted_base* pi_;
};

shared_ptr.h

#pragma once
#include"sysutil.h"
#include"shared_count.h"

template<class Type>
class shared_ptr
{
public:
	typedef shared_ptr<Type>  this_type;
public:
	shared_ptr(Type* p):pn(p),px(p)
	{
#ifdef DISPLAY
		std::cout << "Create SHARED_PTR" << std::endl;
#endif
	}

	shared_ptr(const shared_ptr<Type>& r):px(r.px),pn(r.pn)
	{}

	this_type& operator=(const this_type& r)
	{
		this_type(r).swap(*this);
		return *this;
	}

	Type& operator*()
	{
		return *px;
	}

	Type* operator->()
	{
		return px;
	}

	~shared_ptr()
	{
#ifdef DISPLAY
		std::cout << "Free SHARED_PTR" << std::endl;
#endif
	}

	long use_count()const
	{
		return pn.use_count();
	}

	void swap(shared_ptr<Type>& other)
	{
		std::swap(px, other.px);
		pn.swap(other.pn);
	}

private:
	Type* px;
	shared_count<Type> pn;
};

sp_counted_base.h

#pragma once
#include"sysutil.h"
#include"shared_count.h"

template<class Type>
class shared_ptr
{
public:
	typedef shared_ptr<Type>  this_type;
public:
	shared_ptr(Type* p):pn(p),px(p)
	{
#ifdef DISPLAY
		std::cout << "Create SHARED_PTR" << std::endl;
#endif
	}

	shared_ptr(const shared_ptr<Type>& r):px(r.px),pn(r.pn)
	{}

	this_type& operator=(const this_type& r)
	{
		this_type(r).swap(*this);
		return *this;
	}

	Type& operator*()
	{
		return *px;
	}

	Type* operator->()
	{
		return px;
	}

	~shared_ptr()
	{
#ifdef DISPLAY
		std::cout << "Free SHARED_PTR" << std::endl;
#endif
	}

	long use_count()const
	{
		return pn.use_count();
	}

	void swap(shared_ptr<Type>& other)
	{
		std::swap(px, other.px);
		pn.swap(other.pn);
	}

private:
	Type* px;
	shared_count<Type> pn;
};

sp_counted_impl.h

#pragma once

#include"sysutil.h"
#include"sp_counted_base.h"

template<class X>
class sp_counted_impl:public sp_counted_base
{
public:
	sp_counted_impl(X* px) :px_(px)
	{
#ifdef DISPLAY
		std::cout << "create SP_COUNTED_IMPL" << std::endl;
#endif
	}

	void dispose()
	{
		delete px_;
	}

	~sp_counted_impl()
	{
#ifdef DISPLAY
		std::cout << "Free SP_COUNTED_IMPL" << std::endl;
#endif
	}

private:
	X* px_;
};

sysutil.h

#pragma once
#include<iostream>
#include<vld.h>
//using namespace std;
//#define DISPLAY


test.cpp

#include"shared_ptr.h"

void test01()
{
	int* ptr = new int(5);
	shared_ptr<int> ps(ptr);
	std::cout << "ptr.use_count="<<ps.use_count() << std::endl;

	shared_ptr<int>ps2(ps);
	std::cout << "ptr.use_count=" << ps2.use_count() << std::endl;

	/*{
		shared_ptr<int>ps3(ps2);
		std::cout << "ptr.use_count=" << ps3.use_count() << std::endl;
	}
	std::cout << "ptr.use_count=" << ps2.use_count() << std::endl;

	std::cout << *ps << std::endl;*/

	//int* q = new int(50);
	//shared_ptr<int> ps4(q);
	//std::cout << "q.use_count=" << ps4.use_count() << std::endl;
	{
		int* ptr2 = new int(50);
		shared_ptr<int> ps5(ptr2);
		ps5 = ps;
		std::cout << "ptr2.use_count=" << ps5.use_count() << std::endl;
	}
	std::cout << "ptr2.use_count=" << ps2.use_count() << std::endl;
}

void main()
{
	test01();
	system("pause");
}

weak_ptr:不影响引用计数,也不能解引用

#include<iostream>
#include<vld.h>
using namespace std;

void test01()
{
	int* ptr = new int(10);
	shared_ptr<int> ps(ptr);
	cout << "ptr.use_count=" << ps.use_count() << endl;
    
	weak_ptr<int> pw = ps;
	cout << "ptr.use_count=" << pw.use_count() << endl;//不影响引用计数
	//cout << *pw << endl;//不能解引用
}

void main()
{
	test01();
	system("pause");
}

智能指针:异常安全但不是线程安全的,需要加锁实现互斥

1. 智能指针对象中引用计数是多个智能指针对象共享的,两个线程中智能指针的引用计数同时 ++ -- ,这个操作不是原子的,引用计数原来是 1 ++ 了两次,可能还是 2. 这样引用计数就错乱了。会导致资源未 释放或者程序崩溃的问题。所以只能指针中引用计数 ++ -- 是需要加锁的,也就是说引用计数的操作是 线程安全的。
2. 智能指针管理的对象存放在堆上,两个线程中同时去访问,会导致线程安全问题。
#include<iostream>
#include<mutex>
#include<thread>
//智能指针 异常安全但不线程安全
using namespace std;
template <class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr = nullptr)
		: _ptr(ptr)
		, _pRefCount(new int(1))
		, _pMutex(new mutex)
	{}
	~SharedPtr()
	{
		Release();
	}
	SharedPtr(const SharedPtr<T>& sp)
		: _ptr(sp._ptr)
		, _pRefCount(sp._pRefCount)
		, _pMutex(sp._pMutex)
	{
		AddRefCount();
	}
	SharedPtr<T>& operator=(const SharedPtr<T>& sp)
	{
		if (_ptr != sp._ptr)
		{
			Release();
			_ptr = sp._ptr;
			_pRefCount = sp._pRefCount;
			_pMutex = sp._pMutex;
			AddRefCount();
		}
		return *this;
	}
	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }
	int UseCount() { return *_pRefCount; }
	T* Get() { return _ptr; }
	void AddRefCount()
	{
		_pMutex->lock();
		++(*_pRefCount);
		_pMutex->unlock();
	}
private:
	void Release()
	{
		bool deleteflag = false;
		_pMutex->lock();
		if (--(*_pRefCount) == 0)
		{
			delete _ptr;
			delete _pRefCount;
			deleteflag = true;
		}
		_pMutex->unlock();
		if (deleteflag)
			delete _pMutex;
	}
private:
	int* _pRefCount; // 引用计数
	T* _ptr;       // 指向管理资源的指针
	mutex* _pMutex;
};
class Date
{
public:
	Date() { cout << "Date()" << endl; }
	~Date() { cout << "~Date()" << endl; }
	size_t _year = 0;
	size_t _month = 0;
	size_t _day = 0;
};
mutex mt;
void SharePtrFunc(SharedPtr<Date>& sp, size_t n)
{
	cout << sp.Get() << endl;
	for (size_t i = 0; i < n; ++i)
	{
		SharedPtr<Date> copy(sp);
		mt.lock();
		copy->_year++;
		copy->_month++;
		copy->_day++;
		mt.unlock();
	}
}
int main()
{
	SharedPtr<Date> p(new Date);
	cout << p.Get() << endl;
	const size_t n = 10000000;
	thread t1(SharePtrFunc, ref(p), n);
	thread t2(SharePtrFunc, ref(p), n);
	t1.join();
	t2.join();
	cout << p->_year << endl;
	cout << p->_month << endl;
	cout << p->_day << endl;
	return 0;
}

循环引用:

#include<iostream>
using namespace std;
struct ListNode
{
	int _data;
	/*shared_ptr<ListNode> _prev;
	shared_ptr<ListNode> _next;*/
	weak_ptr<ListNode> _prev;//解决循环引用
	weak_ptr<ListNode> _next;
	~ListNode() { cout << "~ListNode()" << endl; }
};
int main()
{
	shared_ptr<ListNode> node1(new ListNode);
	shared_ptr<ListNode> node2(new ListNode);
	cout << node1.use_count() << endl;
	cout << node2.use_count() << endl;
	node1->_next = node2;
	node2->_prev = node1;
	cout << node1.use_count() << endl;
	cout << node2.use_count() << endl;
	return 0;
}
1. node1 node2 两个智能指针对象指向两个节点,引用计数变成 1 ,我们不需要手动 delete
2. node1 _next 指向 node2 node2 _prev 指向 node1 ,引用计数变成 2
3. node1 node2 析构,引用计数减到 1 ,但是 _next 还指向下一个节点。但是 _prev 还指向上一个节点。
4. 也就是说 _next 析构了, node2 就释放了。
5. 也就是说 _prev 析构了, node1 就释放了。
6. 但是 _next 属于 node 的成员, node1 释放了, _next 才会析构,而 node1 _prev 管理, _prev 属于 node2 成员,所以这就叫循环引用,谁也不会释放。
删除器的使用--属于回调函数
#include<iostream>
#include<vld.h>
using namespace std;

void ptr_delete(void* ptr)
{
	cout << "Free" << endl;
	free(ptr);//delete [] close
}

void test01()
{
	//socket
	int* ptr = (int*)malloc(sizeof(int));//malloc new[]
	shared_ptr<int> ps(ptr, ptr_delete);
}

void main()
{
	test01();
	system("pause");
}

shared_ptr实现的简单版

// 模拟实现一份简单的SharedPtr,了解原理
#include<iostream>
#include <thread>
#include <mutex>
using namespace std;
template <class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr = nullptr)
		: _ptr(ptr)
		, _pRefCount(new int(1))
		, _pMutex(new mutex)
	{}
	~SharedPtr() { Release(); }
	SharedPtr(const SharedPtr<T>& sp)
		: _ptr(sp._ptr)
		, _pRefCount(sp._pRefCount)
		, _pMutex(sp._pMutex)
	{
		AddRefCount();
	}
	// sp1 = sp2
	SharedPtr<T>& operator=(const SharedPtr<T>& sp)
	{
		//if (this != &sp)
		if (_ptr != sp._ptr)
		{
			// 释放管理的旧资源
			Release();
			// 共享管理新对象的资源,并增加引用计数
			_ptr = sp._ptr;
			_pRefCount = sp._pRefCount;
			_pMutex = sp._pMutex;

			AddRefCount();
		}
		return *this;
	}
	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }
	int UseCount() { return *_pRefCount; }
	T* Get() { return _ptr; }
	void AddRefCount()
	{
		// 加锁或者使用加1的原子操作
		_pMutex->lock();
		++(*_pRefCount);
		_pMutex->unlock();
	}
private:
	void Release()
	{
		bool deleteflag = false;

		// 引用计数减1,如果减到0,则释放资源
		_pMutex.lock();
		if (--(*_pRefCount) == 0)
		{
			delete _ptr;
			delete _pRefCount;
			deleteflag = true;
		}
		_pMutex.unlock();

		if (deleteflag == true)
			delete _pMutex;
	}
private:
	int* _pRefCount; // 引用计数
	T* _ptr; // 指向管理资源的指针 
	mutex* _pMutex; // 互斥锁
};
int main()
{
	SharedPtr<int> sp1(new int(10));
	SharedPtr<int> sp2(sp1);
	*sp2 = 20;
	cout << sp1.UseCount() << endl;
	cout << sp2.UseCount() << endl;
	SharedPtr<int> sp3(new int(10));
	sp2 = sp3;
	cout << sp1.UseCount() << endl;
	cout << sp2.UseCount() << endl;
	cout << sp3.UseCount() << endl;
	sp1 = sp3;
	cout << sp1.UseCount() << endl;
	cout << sp2.UseCount() << endl;
	cout << sp3.UseCount() << endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值