欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

类-unique_ptr实现原理

程序员文章站 2022-03-22 20:57:53
...

1.管理内存的原理

C++新标准库中采两个智能指针类型来管理动态对象,share_ptr允许多个指针指向同一个对象;
unique_ptr则“独占”所指对象。
对于unique_ptr<T>我们可以按如下方式使用去管理堆内存,相比于new,省去使用delete去释放内存的麻烦。
void use_factory(T arg)
{
	unique_ptr_ptr<Foo> p = factory(arg);
	Foo *ptr = new Foo(arg);
	
	//使用P
}//p离开了作用域,但它指向的内存会被释放掉
 //ptr申请的内存没有被释放,造成了内存泄漏

我们知道指针或引用在离开作用域时是不会进行析构的,但类在离开作用域时会自动执行析构函数(unique_ptr
本质是类,只是可以像指针一样使用)
,因此,我们可以通过析构函数调用delete去销毁资源。
那unique_ptr如何实现“独占”所指对象,因为unique_ptr本质是类,因此可将copy constructor和copy assignment声明为delete即可(获取将其变为private属性且不去实现它也行);
同时我们需要实现移动构造和移动赋值,以供某些特定场合使用。

2.unique_ptr的实现

示例中定义了一个HasPtr类去管理一个string对象,其类的定义如下,为了方便调试,每个类
均有打印信息。由于存在移动函数,其他函数在使用资源前,应答进行合法判断,保证函数正确执行
①类定义
#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;
using std::ostream;
 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class HasPtr{
	friend ostream& operator<<(ostream&, const HasPtr&);
public:
	//构造函数 
	HasPtr(const string &s = string()):ps(new string(s))
		{cout<< "HasPtr(const string &s = string())"<<endl;}	
	
	HasPtr(HasPtr&& rhs) noexcept :ps(rhs.ps)
		{rhs.ps = nullptr; cout<< "HasPtr(HasPtr&&)"<<endl;}
		
	//拷贝构造函数   
	HasPtr& operator=(HasPtr &&p) noexcept;
	
	HasPtr(const HasPtr&) = delete;			//拷贝构造与赋值不能使用 
	HasPtr& operator=(const HasPtr&) = delete;
	
	//虚构函数 
	~HasPtr();
private:	
	string *ps;
};
②.删除拷贝构造和拷贝赋值函数
HasPtr(const HasPtr&) = delete;			//拷贝构造与赋值不能使用 
HasPtr& operator=(const HasPtr&) = delete;
③移动赋值实现
先销毁左测资源,再移动右值资源给左值,最后清空右侧资源
inline
HasPtr& HasPtr::operator=(HasPtr &&rhs) noexcept
{
	cout<< "HasPtr& operator=(HasPtr &&rhs)";
	if(this != &rhs)
	{
		if(ps)
		{
			cout<< " delete:"<< *ps;
			delete ps;
		}
			
		ps    = rhs.ps;
		rhs.ps = nullptr;
	}
	cout<<endl;
	return *this;
}
③.析构的实现
inline
HasPtr::~HasPtr()
{
	cout<< "~HasPtr()";
	if(ps) 
	{
		cout<< " delete:"<< *ps;
		delete ps;
	}
	cout<<endl;
	
}
④.打印函数
inline
ostream& operator<<(ostream& os, const HasPtr& ptr)
{
	if(ptr.ps) 
		os << *ptr.ps; 
	else
		os << "empty class!!";
	return os; 
}
⑤.调试程序 
int main(int argc, char** argv) {
	cout<< "1.构造函数"<< endl;
	HasPtr ptr1("first!");		//打印:HasPtr(const string &s = string())
	HasPtr ptr2("second!");		//打印:HasPtr(const string &s = string())
	cout<<endl;
	
	cout<< "2.移动赋值"<< endl;
	//ptr1 = ptr2;    		//错误:ptr1是左值 
	ptr1 = std::move(ptr2);		//打印:HasPtr& operator=(HasPtr &&rhs) delete:first!
	cout << "ptr1:" << ptr1 << endl; //打印:ptr1:second!
	cout << "ptr2:" << ptr2 << endl; //打印:ptr2:empty class!!
	cout<<endl;
	
	cout<< "3.移动构造"<< endl;
	HasPtr ptr3(std::move(ptr1)); //打印:HasPtr(HasPtr&&)
	cout << "ptr1:" << ptr1 << endl; //打印:ptr1:empty class!!
	cout << "ptr2:" << ptr2 << endl; //打印:ptr1:empty class!!
	cout << "ptr3:" << ptr3 << endl; //打印:ptr3:second!
	cout<<endl;
	
	cout<< "程序结束"<< endl;
	//打印:
	//~HasPtr() delete:second!
	//~HasPtr()
	//~HasPtr() 
	return 0;
}