类-share_ptr实现原理

1.引用计数管理内存的原理

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

我们知道指针或引用在离开作用域时是不会进行析构的,但类在离开作用域时会自动执行析构函数(从这也可看出share_ptr本质是类,只是模仿出指针使用的效果而已),因此,
我们可以通过析构函数调用delete去销毁资源。
那share_ptr如何实现多个类同时指向同一个对象,这就产生了引用计数,它实际是一个整形指针,让多个
对象共享其指向的对象,该对象记录着当前有多少个对象在共享同一变量
share_ptr get_factory(T arg)
 {
	share_ptr p = factory(arg);  //引用计数值为1,同时new一个Foo对象
	
	share_ptr tmp = factory(arg);//创建一个临时的tmp, 
	tmp = p; //进行赋值操作时,右侧P递增引入计数值为2,左侧tmp递减引入计数值为0,
			 //销毁上句创建的资源后再将指针指向与p同样的资源
	
	return p; //当返回p时,引用计数进行了递增操作值为3
	
 }//tmp离开作用域时,调用析构函数引用计数递减到2
  //p离开作用域时,调用析构函数引用计数递减到1,表示还有一个对象享有Foo对象

根据上述例子我们知道shared_ptr通过拷贝构造和拷贝赋值函数递增或递减引用计数。

2.引用计数的实现(可参考c++ primer 13.2.2章节)

示例中定义了一个HasPtr类去管理一个string对象,其类的定义如下,为了便宜调试,每个类

均有打印信息。

①类定义

#include 
#include 
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&);
	
	friend void swap(HasPtr& lhs, HasPtr& rhs); 
		 
public:
	//构造函数 
	HasPtr(const string &s = string()):ps(new string(s)),use(new std::size_t(1)) 
		{cout<< "call: HasPtr()"<
②.拷贝赋值的实现
拷贝赋值时为了避免自赋值的情况,本例采用swap的方式实现,基本过程是左侧对象执行一次析构后执行拷贝构造操作。
inline
void swap(HasPtr& lhs, HasPtr& rhs){
	using std::swap;
	swap(lhs.ps, rhs.ps);
	swap(lhs.use, rhs.use); 	
} 

inline 
HasPtr& HasPtr::operator=(HasPtr p){
	cout<< "void swap(HasPtr& lhs, HasPtr& rhs)"<
③.析构的实现
HasPtr::~HasPtr()
{
	cout<< "HasPtr::~HasPtr():"<< *this <
④.打印函数
inline
ostream& operator<<(ostream& os, const HasPtr& ptr)
{
	os << *ptr.ps << " " << *ptr.use; 
	return os; 
}
⑤.调试程序
int main(int argc, char** argv) 
{
	cout << "1.构造函数" << endl;
	HasPtr ptr1("first"); 				//打印:call: HasPtr()
	HasPtr ptr2("sencond");				//打印:call: HasPtr()
	cout << "" << endl; 

	cout << "2.拷贝构造" << endl;
	HasPtr ptr3(ptr2);			//打印:call: HasPtr(const HasPtr& p)
	cout << "ptr1: " << ptr1 << endl; //打印:ptr1: first 1
	cout << "ptr2: " << ptr2 << endl; //打印:ptr2: sencond 2
	cout << "ptr3: " << ptr3 << endl; //打印:ptr3: sencond 2
	cout << "" << endl; 

	cout << "3.不同对象之间的赋值" << endl; 
	ptr1 = ptr3;	//打印:call: HasPtr(const HasPtr& p),
					//HasPtr& HasPtr::operator=(HasPtr p)
					//HasPtr::~HasPtr():first 1
					//delete ps; delete use;
	cout << "ptr1: " << ptr1 << endl; //打印:ptr1: sencond 3
	cout << "ptr2: " << ptr2 << endl; //打印:ptr2: sencond 3
	cout << "ptr3: " << ptr3 << endl; //打印:ptr3: sencond 3
	cout << "" << endl; 

	cout << "4.指向类型相同赋值" << endl; 
	ptr1 = ptr3;	//打印:call: HasPtr(const HasPtr& p)
					//HasPtr& HasPtr::operator=(HasPtr p)
					//HasPtr::~HasPtr():first 1
					//delete ps; delete use;
	cout << "ptr1: " << ptr1 << endl; //打印:ptr1: sencond 3
	cout << "ptr2: " << ptr2 << endl; //打印:ptr2: sencond 3
	cout << "ptr3: " << ptr3 << endl; //打印:ptr3: sencond 3
	cout << "" << endl; 

	cout << "5.自符值" << endl;
	ptr1 = ptr1;   //打印:call: HasPtr(const HasPtr& p)
					//HasPtr& HasPtr::operator=(HasPtr p)
					//HasPtr::~HasPtr():sencond 4
	cout << "ptr1: " << ptr1 << endl; //打印:ptr1: sencond 3
	cout << "ptr2: " << ptr2 << endl; //打印:ptr2: sencond 3
	cout << "ptr3: " << ptr3 << endl; //打印:ptr3: sencond 3
	cout << "" << endl; 

	cout << "程序结束" << endl;
	//打印:
	//HasPtr::~HasPtr():sencond 3
	//HasPtr::~HasPtr():sencond 2
	//HasPtr::~HasPtr():sencond 1
	//delete ps; delete use;
	return 0;
}






你可能感兴趣的:(C/C++)