C++智能指针

智能指针是防止在抛出异常后,直接跳到catch(),导致内存泄漏或在多线程的情况下发生死锁导致程序无法进行。

比如:

	template<class T>
	class SmartPtr
	{
	public:
		SmartPtr(T* ptr)
			:_ptr(ptr)
		{ }
		~SmartPtr()
		{
			if (_ptr)
			{
				cout << "~SmartPtr():" << endl;
				//delete _ptr;
				//_ptr = nullptr;
			}
		}
	private:
		T* _ptr;
	};


void fun1()
{
	int a, b;
	cin >> a >> b;
	int* p = new int(a);
	SmartPtr<int> sp(p);
	if (b == 0)
	{
		throw "b==0?";
	}
	int c = a / b;

}
void test1()
{
	try
	{
		fun1();
	}
	catch (const char* errsmg)
	{
		cout << errsmg << endl;
	}
}

在跳出fun1()函数是就会自动调用sp的析构函数。

但会出现多个指针管理同一资源的情况,导致重复释放问题,一下几种解决方式。

1. auto_ptr

管理权转移,原来的指针置空。

	template<class T>
	class AutoPtr
	{	public:
		AutoPtr(T* ptr)
			:_ptr(ptr)
		{ }


		~AutoPtr()
		{
			if (_ptr)
			{
				cout << "~AutoPtr():" << endl;
				delete _ptr;
				_ptr = nullptr;
			}
		}

		AutoPtr(AutoPtr<T>& at)
		{
			_ptr = at._ptr();
			at._ptr = nullptr;
		}

		void operator=(AutoPtr<T>& at)
		{
			delete _ptr;
			_ptr = nullptr;
			_ptr = at._ptr;
			at._ptr = nullptr;
		}
	private:
		T* _ptr;
	};

这种方式使原来是指针不能再使用了,悬空,不建议使用。

2.unique_ptr

禁止拷贝,一个资源只能由于一个智能指针管理。

	template<class T>
	class uniqueptr
	{
	public:
		uniqueptr(T* ptr)
			:_ptr(ptr)
		{
		}
		~uniqueptr()
		{
			if (_ptr)
			{
				cout << "~uniqueptr():" << endl;
				delete _ptr;
				_ptr = nullptr;
			}
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		uniqueptr(const uniqueptr<T>& uq) = delete;
		void operator=(const uniqueptr<T>& uq) = delete;

	private:
		T* _ptr;
	};

3.shared_ptr

共享指针,一块资源可以有多个智能指针管理,但为了只允许释放一次(最后一个智能指针释放),添加了计数器,当减减之后为计数为0就释放。

	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr)
			:_ptr(ptr)
			,_pcount(new int(1))
		{
			cout << "构造函数:" << *_pcount << endl;
		}


		~shared_ptr<T>()
		{
			if (--(*_pcount) <= 0 && _ptr)
			{
				cout << "~shared_ptr():" << *_pcount + 1 << "-->" << *_pcount << endl;
				delete _ptr;
				_ptr = nullptr;
				delete _pcount;
				_pcount = nullptr;
			}
			else
			{
				cout << "没有析构:" << (*_pcount) + 1 << "-->" << *_pcount << endl;
			}
		}


		shared_ptr<T>(const shared_ptr<T>& sp)
		{
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			(*_pcount)++;
			cout << "拷贝构造shared_ptr():" << (*_pcount) -1<< "-->" << *_pcount << endl;

		}


		void operator=(const shared_ptr<T>& sp)
		{
			delete _ptr;
			_ptr = nullptr;
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			(*_pcount)++;
			cout << "赋值重载void operator=" << (*_pcount)-1 << "-->" << *_pcount << endl;
		}

		int& Getcount()
		{
			return *_pcount;
		}


	private:
		T* _ptr;
		int* _pcount;    //  用于统计管理该指针对于内存的对象的个数,当为0时,该空间可以delete
	};

void test4()
{
	GuYu::shared_ptr<int> sp(new int(1));
	GuYu::shared_ptr<int> sp1 = sp;

}


结果:
构造函数:1
拷贝构造shared_ptr():1-->2
没有析构:2-->1
~shared_ptr():1-->0

只在最后一个管理者析构时释放。

有了计数就要考虑线程安全问题,因为什么时候析构依赖于*_pcount,当线程冲突导致*_pcount少于实际存在的智能指针的数量时,导致重复释放空间。

需要加一把锁,并且每个管理的智能指针用的是同一把锁。

锁是不支持拷贝构造的,他们的拷贝构造函数都被delete了。

线程安全:

	template<class T>
	class shared_ptr2
	{
	public:
		shared_ptr2(T* ptr=nullptr)
			:_ptr(ptr)
			,_pcount(new int(1))
			,_mtx(new mutex)
		{
			cout << "构造函数:" << *_pcount << endl;
		}



		~shared_ptr2<T>()
		{
			bool flag = false;
			_mtx->lock();
			if (--(*_pcount) == 0 && _ptr)
			{
				cout << "~shared_ptr2():" << *_pcount + 1 << "-->" << *_pcount << endl;
				delete _ptr;
				_ptr = nullptr;
				delete _pcount;
				_pcount = nullptr;
				flag = true;
			}
			else
			{
				cout << "没有析构:" << (*_pcount) + 1 << "-->" << *_pcount << endl;
			}
			_mtx->unlock();
			if (flag)
			{
				delete _mtx;
				_mtx = nullptr;
			}
		}


		shared_ptr2<T>(const shared_ptr2<T>& sp)
		{
			sp._mtx->lock();
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			_mtx = sp._mtx;
			(*_pcount)++;
			cout << "拷贝构造shared_ptr2():" << (*_pcount) -1<< "-->" << *_pcount << endl;
			sp._mtx->unlock();
		}


		void operator=(const shared_ptr2<T>& sp)
		{
			sp._mtx->lock();
			delete _ptr;
			delete _mtx;
			_ptr = nullptr;
			_mtx = nullptr;
			_mtx = sp._mtx;
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			(*_pcount)++;
			cout << "赋值重载void operator=" << (*_pcount)-1 << "-->" << *_pcount << endl;
			sp._mtx->unlock();

		}


		T& operator*()
		{return *_ptr;}

		T* operator->()
		{return _ptr;}

		T& operator[](size_t pos)
		{return _ptr[pos];}

		T* Getptr()
		{return _ptr;}

		int& Getcount()
		{return *_pcount;}


	private:
		T* _ptr;
		int* _pcount;    //  用于统计管理该指针对于内存的对象的个数,当为0时,该空间可以delete
		mutex* _mtx;     //用同一把锁
	};

循环引用问题

struct Node
{
	Node()
		:val(0)
		,_next(nullptr)
		,_prev(nullptr)
	{ }
	~Node()
	{
		cout << "~Node()" << endl;
	}
	shared_ptr2<Node> _prev;
	shared_ptr2<Node> _next;
	//Node* _prev;
	//Node* _next;
	int val;


};
void test6()
{
	shared_ptr2<Node> sp1(new Node);
	shared_ptr2<Node> sp2(new Node);
	sp1.Getptr()->_next = sp2;
	sp2.Getptr()->_prev = sp1;    //  没有被析构释放

}

结果:
构造函数:1    //_prev
构造函数:1    //_next
构造函数:1    //_sp1
构造函数:1    //_prev
构造函数:1    //_next
构造函数:1    //_sp2
赋值重载void operator=1-->2
赋值重载void operator=1-->2
没有析构:2-->1
没有析构:2-->1

可见,并没有成功释放空间,sp1等待着sp2的_prev释放,sp1走了,同时带走了sp1的_next,也就是sp2的一个_pcount,但sp2的_pcount没有减减,导致sp2走了,也没有释放空间。

那么对于_prev和_next就不参与_pcount的加减。

	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr() = default;     //  显示默认构造函数

		weak_ptr(const shared_ptr2<T>& sp)
		{
			cout << "weak_ptr(const shared_ptr2<T>& sp)拷贝:" << endl;
			_ptr = sp._ptr;
		}

		weak_ptr<T>& operator=(shared_ptr2<T>& sp)
		{
			cout << "weak_ptr<T>& operator=(const shared_ptr2<T>& sp)赋值重载:" << endl;
			_ptr = sp.Getptr();
			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		T& operator[](size_t pos)
		{
			return _ptr[pos];
		}
	private:
		T* _ptr;
	};

}

struct Node
{
	Node()
		:val(0)
	{ }
	GuYu::weak_ptr<Node> _prev;   //  调用默认构造函数
    GuYu::weak_ptr<Node> _next;
	int val;


};

shared_ptr的delete使用

int i = 0;
class A
{
public:
	A() = default;
	~A()
	{
		cout <<i++<<" : "<< "~A()" << "  ";
	}
	A(int n)
	{
		;
	}
private:
};


template<class A>
class DeleteArr
{
public:
	void operator()(A* arr)
	{
		cout << "delete [] arr" << endl;
		delete[]arr;
		cout << endl;
		cout << "over delete [] arr" << endl;
	}
};


template<class A>
class Free
{
public:
	void operator()(A* arr)
	{
		cout << "free [] arr" << endl;
		free(arr);
		cout << "over free [] arr" << endl;
	}
};

template<class A>
class Closefile
{
public:
	void operator()(A* pf)
	{
		cout << "Closefile [] arr" << endl;
		fclose(pf);
		cout << "over Closefile [] arr" << endl;
	}
};


void test7()
{
	std::shared_ptr<A> sp1(new A);
	//std::shared_ptr<A> sp2(new A[10]);  //  会发生 异常
	std::shared_ptr<A> sp2(new A[10], DeleteArr<A>());             //  C++11
	std::shared_ptr<A> sp3(new A[10], [](A* p) {cout << endl;; cout << "lambda" << endl;; delete[]p; cout << endl; });   //  C++11
	std::shared_ptr<A[]> sp4(new A[10]);  //                     C++17


	//std::shared_ptr<A>sp5((A*)malloc(sizeof(A) * 10));        //  内存泄漏,没有释放
	std::shared_ptr<A>sp5((A*)malloc(sizeof(A) * 10),Free<A>()); 


	FILE* pf;
	errno_t err = fopen_s(&pf, "test.txt", "w");
	std::shared_ptr<FILE> sp6(pf,Closefile<FILE>());
}


结果:
Closefile [] arr
over Closefile [] arr
free [] arr
over free [] arr
0 : ~A()  1 : ~A()  2 : ~A()  3 : ~A()  4 : ~A()  5 : ~A()  6 : ~A()  7 : ~A()  8 : ~A()  9 : ~A()
lambda
10 : ~A()  11 : ~A()  12 : ~A()  13 : ~A()  14 : ~A()  15 : ~A()  16 : ~A()  17 : ~A()  18 : ~A()  19 : ~A()
delete [] arr
20 : ~A()  21 : ~A()  22 : ~A()  23 : ~A()  24 : ~A()  25 : ~A()  26 : ~A()  27 : ~A()  28 : ~A()  29 : ~A()
over delete [] arr
30 : ~A()

只能在堆上创建对象

class OnlyHeap   //  禁止调用默认构造函数,赋值重载,拷贝函数
{
public:
	static OnlyHeap* Getobj()   //  静态变量不需要实例化对象就可以使用
	{
		return new OnlyHeap; // 调用默认构造函数
	}
	OnlyHeap(const OnlyHeap& hp) = delete;
	void operator=(const OnlyHeap& hp) = delete;
private:
	OnlyHeap() {};
};

void test9()
{
	OnlyHeap* hp = OnlyHeap::Getobj();  
	  // OnlyHeap hp2(*hp);   已被删除的函数
}

只能在栈上创建对象

class OnlyStack       //  只要禁止new调用默认构造函数
{
public:
	static OnlyStack Getobj()
	{
		return OnlyStack();
	}

	 // void* operator new(size_t size) = delete;   // 如果只写这种方式,会有缺陷,当创建的对象是静态的   -->  static OnlyStack sk= new OnlyStack ;   就不会受限制
private:
	OnlyStack() {};
};
void test10()
{
	OnlyStack sk = OnlyStack::Getobj();
	// OnlyStack* sk2 = new OnlyStack;   //  默认构造函数无法访问
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值