09 智能指针

01 基础知识

智能指针:保证能做到资源的自动释放;是利用栈上的对象出作用域自动析构的特征,来做到资源的自动释放的。

// CSmartPtr<int> *p = new CSmartPtr<int>(new int); delete p;裸指针(在堆上)
template<typename T>
class CSmartPtr
{
public:
	CSmartPtr(T *ptr=nullptr)
		:mptr(ptr){}
	~CSmartPtr() 
	{ 
		delete mptr;
		mptr = nullptr;
	}
	
	// 重载解引用操作符
	T& operator*() { return *mptr; }
	// 重载箭头操作符
	T* operator->() { return mptr; }
private:
	T* mptr;
};

堆内存管理示例(使用智能指针)

CSmartPtr<int> ptr1(new int);

堆内存管理示例(手动管理)

// data堆 heap堆 stack堆
int* p = new int(10);
*p = 10;
delete p;

auto_ptr 是C++98标准库中的智能指针类型,但由于其语义不明确且容易导致资源管理问题,它在C++11中被弃用。auto_ptr的问题主要在于其复制语义:复制一个 auto_ptr 会将资源的所有权从一个auto_ptr 转移到另一个,而不是复制资源。
scoped_ptr 是Boost库中的一种智能指针类型,它不支持复制和赋值操作,这意味着每个 scoped_ptr 都是唯一拥有资源的所有权。C++标准库中没有直接的 scoped_ptr,但可以使用类似的 unique_ptr

不带引用计数的智能指针
这些代码的目的是确保 scoped_ptr 和 unique_ptr 对象是唯一拥有其管理的资源的,并且不允许被复制,从而防止多个智能指针同时管理同一资源。

删除复制构造函数和复制赋值操作符

  • 复制构造函数: 当一个对象被复制初始化(例如 scoped_ptr p2(p1);)时调用。
  • 复制赋值操作符: 当一个对象被复制赋值(例如 p2 = p1;)时调用。
// C++11新标准:
// scoped_ptr
	// 删除复制构造函数和复制赋值操作符
	scoped_ptr(const scoped_ptr<T>&) = delete;
	scoped_ptr<T>& operator=(const scoped_ptr<T>&) = delete;

// 推荐使用:
// unique_ptr
	unique_ptr(const unique_ptr<T>&) = delete;
	unique_ptr<T>& operator=(const unique_ptr<T>&) = delete;

怎么解决浅拷贝的问题!!!

	//CSmartPtr<int> p1(new int);
	//CSmartPtr<int> p2(p1);

	auto_ptr<int> ptr1(new int);
	auto_ptr<int> ptr2(ptr1);

	*ptr2 = 20;
	cout << *ptr1 << endl;

// 不推荐使用auto_ptr进行vector<auto_ptr<int>> vec1; vec2(vec1);
// std::move => C++11 右值引用 std::move得到当前变量的右值类型
int main() 
{
	
	unique_ptr<int> p1(new int);
	unique_ptr<int> p2(std::move(p1));

	return 0;
}

02 shared_ptr和weak_ptr

带引用计数的智能指针shared_ptrweak_ptr
带引用计数:

  • 多个智能指针可以管理同一个资源
  • 给每一个对象资源,匹配一个引用计数;

智能指针 =》使用资源的时候 =》引用计数+1
智能指针 =》不使用资源的时候 =》引用计数-1 =》!=0 等于0时资源释放了

// 对资源进行引用计数的类
template<typename T>
class RefCnt
{
public:
	RefCnt(T* ptr = nullptr)
		:mptr(ptr)
	{
		if (mptr != nullptr)
			mcount = 1;
	}
	void addRef() { mcount++; } // 增加资源的引用计数
	int delRef() { return --mcount; }
private:
	T* mptr;
	int mcount;
};

template<typename T>
class CSmartPtr
{
public:
	CSmartPtr(T* ptr = nullptr)
		:mptr(ptr) 
	{
		mpRefCnt = new RefCnt<T>(mptr);
	}
	~CSmartPtr()
	{
		if (0 == mpRefCnt->delRef())
		{
			delete mptr;
			mptr = nullptr;
		}
	}

	T& operator*() { return *mptr; }
	T* operator->() { return mptr; }

	CSmartPtr(const CSmartPtr<T>& src)
		:mptr(src.mptr),mpRefCnt(src.mpRefCnt)
	{
		if (mptr != nullptr)
			mpRefCnt->addRef();
	}
	CSmartPtr<T>& operator=(const CSmartPtr<T>& src)
	{
		if (this == &src)
			return *this;
		if (0 == mpRefCnt->delRef())
			delete mptr;
		mptr = src.mptr;
		mpRefCnt = src.mpRefCnt;
		mpRefCnt->addRef();
		return *this;
	}
private:
	T* mptr; // 指向该资源的指针
	RefCnt<T>* mpRefCnt; // 指向该资源引用计数对象的指针
};

int main()
{
	CSmartPtr<int> ptr1(new int);
	CSmartPtr<int> ptr2(ptr1);

	CSmartPtr<int> ptr3;
	ptr3 = ptr2;
	*ptr1 = 20;
	cout << *ptr2 << " " << *ptr3 << endl;
	return 0;
}

03 shared_ptr的交叉引用问题

shared_ptr:强智能指针,可以改变资源的引用计数
weak_ptr:弱智能指针,不会改变资源的引用计数
operator* operator->
weak_ptr =>(观察) shared_ptr =>(观察) 资源(内存)

强智能指针循环引用(交叉引用)是什么问题?什么结果?怎么解决?
造成new出来的资源无法释放!!!资源泄露问题
定义对象的时候,用强智能指针;引用对象的地方,使用弱智能指针

class B;
class A
{
public:
	A() { cout << "A()" << endl; }
	~A() { cout << "~A()" << endl; }
	weak_ptr<B> _ptrb;
private:
};
class B
{
public:
	B() { cout << "B()" << endl; }
	~B() { cout << "~B()" << endl; }
	weak_ptr<A> _ptra;
};

int main()
{
	shared_ptr<A> pa(new A());
	shared_ptr<B> pb(new B());

	pa->_ptrb = pb;
	pb->_ptra = pa;

	cout << pa.use_count() << endl;
	cout << pb.use_count() << endl;

	return 0;
}

04 多线程访问共享对象的线程安全问题

C++开源网络库muduo库
多线程访问共享对象的线程安全问题

class A
{
public:
	A() { cout << "A()" << endl; }
	~A() { cout << "~A()" << endl; }
	void testA() { cout << "非常好用的方法!" << endl; }
};
// 子线程
void handler01(weak_ptr<A> pw)
{
	std::this_thread::sleep_for(std::chrono::seconds(2));
	 // q访问A对象的时候,需要侦测以下A对象是否存活
	shared_ptr<A> sp = pw.lock();
	if (sp != nullptr)
	{
		sp->testA();
	}
	else
	{
		cout << "A对象已经析构,不能再访问!" << endl;
	}
}
// main线程
int main()
{
	{
		shared_ptr<A> p(new A());
		thread t1(handler01, weak_ptr<A>(p));
		t1.detach();
	}
	std::this_thread::sleep_for(std::chrono::seconds(20));

	return 0;
}

05 删除器

智能指针的删除器 deletor
智能指针:能够保证资源绝对的释放 delete ptr;

// unique_ptr shard_ptr
~unique_ptr(){ 是一个函数对象的调用 deletor(ptr);}
template<typename T>
class default_delete
{
public:
	void operator()(T *ptr)
	{
		delete ptr;
	}
};
template<typename T>
class MyDeletor
{
public:
	void operator()(T* ptr)const
	{
		cout << "call MyDeletor.operator()" << endl;
		delete[]ptr;
	}
};

template<typename T>
class MyFileDeletor
{
public:
	void operator()(T* ptr)const
	{
		cout << "call MyFileDeletor.operator()" << endl;
		fclose(ptr);
	}
};
int main()
{
	// unique_ptr<int, MyDeletor<int>> ptr1(new int[100]); // delete []ptr; 
	// unique_ptr<FILE,MyFileDeletor<FILE>> ptr2(fopen("data.txt", "w"));

	//lambda表达式 =》函数对象 function
	unique_ptr<int, function<void(int*)>>ptr1(new int[100],
		[](int* p)->void {
			cout << "call lambda release new int[100]" << endl;
			delete[]p;
		});
	unique_ptr<FILE, function<void(FILE*)>>ptr2(fopen("data.txt","w"),
		[](FILE* p)->void {
			cout << "call lambda release new fopen" << endl;
			fclose(p);
		});

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值