c++智能指针的使用,auto_ptr,shared_ptr

今天写程序时想用智能指针与vector容器一起解决指针数组的成员管理问题。在我的程序中我用到了多个指针容器,这样就导致了一个问题,这些指针容器的清空非常繁琐,我不能仅仅调用一次clear就能完成,我需要每次从容器中取出一个元素,然后释放掉这个元素所占的内存,之后再清除掉指针,然后再清空容器。我觉得很是麻烦,于是想将其改进,我不需要去管理容器内的这些指针,当容器被清空或者销毁时,我希望这些元素所占的内存也都被释放掉。于是,我想到了智能指针,现将今天的整个过程记录下来,以免日后再犯同样的错误,同时也希望为存在同样疑惑的同学通俗的说明这个问题。

所谓智能指针,我所理解的就是其能够判断该指针的生存周期,在指针的生存周期外对其所占用的内存进行自动释放,而不需要程序员进行主动控制。对于c++的智能指针,我首先想到的是《Thingking in C++》中提到的auto_ptr,于是我就首先想采用auto_ptr来实现。首先定义一个类,重载new和delete操作符,以便我们能看到具体在使用过程中发生了什么。

class CSmart
{
public:
	CSmart(void);
	~CSmart(void);
	CSmart(int i):i(i){}
private:
	int i;
public:
	static void * operator new(size_t size){
		void *p = ::operator new(size);
		cout<<"Allocting TraceHeap object on the heap at address "<<p<<endl;
		return p;
	}
	static void  operator delete(void *p){
		cout<<"Deleting TraceHeap object at address "<<p<<endl;
		::operator delete (p);
	}
	int getVal() const { return i ;}
};
然后我们首先来试验下auto_ptr的作用

void test_smart_ptr()
{
	auto_ptr<CSmart> pCSmart(new CSmart(5));
	cout<<pCSmart->getVal()<<endl;
}
int main()
{
 test_smart_ptr();
system("pause");
return 0;
}
输入结果如下:

我们看到在程序运行结束的时候申请的那块内存被成功释放,程序员并没有主动释放。好的,这正是我们想要的功能,那么我们试试赋值的结果,我们把test_smart_ptr的代码改为如下内容:

void test_smart_ptr()
{
	auto_ptr<CSmart> pCSmart(new CSmart(5));
	cout<<"ori "<<pCSmart->getVal()<<endl;

	auto_ptr<CSmart> pCopy;
	pCopy = pCSmart;

	cout<<"copy "<<pCopy->getVal()<<endl;

	//cout<<pCSmart->getVal()<<endl;//Error! 内存读取错误
}

我们发现ok,这一切都是没有问题的,那么我们把上面代码中注释掉的那一行取消掉注释会是什么样的结果呢?

我们发现出现了错误,程序不能运行了,这可如何是好,从错误中我们大概知道是读取了非法的内存地址,那么为什么会出现这样的情况呢,原来是C++标准中定义的auto_ptr中对“=”操作符重载的定义中时将赋值后的值抢夺掉原有值的管理所有权,这样就导致了原有值的不可用。这样,我们自然就想到了本来我们要解决的指针容器自动管理的问题,我们知道在向容器中添加元素的时候,其实就是赋值的操作,现在由于“=”问题,导致其不可用。看来,auto_ptr这个东西在一个函数内作为临时变量是比较好用的,其余的就不那么好用了,在好多资料上关于auto_ptr的使用有这么几点说明:

1、auto_ptr不能共享所有权。
2、auto_ptr不能指向数组
3、auto_ptr不能作为容器的成员。
4、不能通过赋值操作来初始化auto_ptr
std::auto_ptr<int> p(new int(42));     //OK
std::auto_ptr<int> p = new int(42);    //ERROR
这是因为auto_ptr 的构造函数被定义为了explicit
5、不要把auto_ptr放入容器

那么,还有没有其他方法解决本文最开始的问题呢,肯定是有的,于是我们发现了shared_ptr,shared_ptr原来是Boost库中的内容,现在c++11新标准的发布,将其加入到了c++标准库中,可以不必使用Boost库而直接使用。那么我们来改写上面的例子:

void test_smart_ptr()
{
	shared_ptr<CSmart> pCSmart(new CSmart(5));
	cout<<"ori "<<pCSmart->getVal()<<endl;

	shared_ptr<CSmart> pCopy;
	pCopy = pCSmart;

	cout<<"copy "<<pCopy->getVal()<<endl;

	cout<<"ori again "<<pCSmart->getVal()<<endl;
}
结果如下:


我们发现一切正常,好的,那么我们来用容器和只能指针实现对指针容器的管理吧。

void test_smart_ptr()
{
	vector<shared_ptr<CSmart>> smart_ptr_vector;

	shared_ptr<CSmart> pCSmart1(new CSmart(5));
	shared_ptr<CSmart> pCSmart2(new CSmart(10));
	shared_ptr<CSmart> pCSmart3(new CSmart(15));

	smart_ptr_vector.push_back(pCSmart1);
	smart_ptr_vector.push_back(pCSmart2);
	smart_ptr_vector.push_back(pCSmart3);


	for(vector<shared_ptr<CSmart>>::iterator it = smart_ptr_vector.begin();it != smart_ptr_vector.end(); it++)
		cout<<(*it)->getVal()<<endl;//访问其中的每一个元素
}
ok,看运行结果,一切正常,这就是我们要的结果,之后可以按照vector中存入的为普通变量进行处理。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章