智能指针auto_ptr介绍

      我们大家都知道,new一定要和delete配合使用,但是有一种情况可能会使这种配对失效,如下程序:

#include <iostream>
using namespace std;
class normal_pointer_example
{
public:
	normal_pointer_example(){cout<<"构造函数执行!\n";}
	~normal_pointer_example(){cout<<"析构函数执行!\n";}
};
class normal_pointer_wrong{};//normal_pointer_wrong异常
bool quit;
void quit_func()
{
	if(quit==true)
		cout<<"调用quit_func函数!\n";
	throw normal_pointer_wrong();
}
int main()
{
	try
	{
		normal_pointer_example *Npointer=new normal_pointer_example;
		quit=true;
		quit_func();
		delete Npointer;
	}
	catch (normal_pointer_wrong)
	{
		cout<<"输出normal_pointer_wrong异常!!\n";
	}
	return 0;
}

  该程序的输出结果为:

      注意上面这个输出,我们看到当程序全部执行完了都没有能够调用析构函数将对象析构掉!这就说明并没有把对象delete掉!!这个就是问题,因为这样就有可能产生不易察觉的内存泄露。

      针对上面这个情况,我们就要使用智能指针类auto_ptr来避免这种情况出现。们来看一个auto_ptr类的声明:

  1 template<class _Ty>
2 class auto_ptr
3 { // wrap an object pointer to ensure destruction
4 public:
5 typedef _Ty element_type;
6
7 explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
8 : _Myptr(_Ptr)
9 { // construct from object pointer
10 }
11
12 auto_ptr(auto_ptr<_Ty>& _Right) _THROW0()
13 : _Myptr(_Right.release())
14 { // construct by assuming pointer from _Right auto_ptr
15 }
16
17 auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()
18 { // construct by assuming pointer from _Right auto_ptr_ref
19 _Ty *_Ptr = _Right._Ref;
20 _Right._Ref = 0; // release old
21 _Myptr = _Ptr; // reset this
22 }
23
24 template<class _Other>
25 operator auto_ptr<_Other>() _THROW0()
26 { // convert to compatible auto_ptr
27 return (auto_ptr<_Other>(*this));
28 }
29
30 template<class _Other>
31 operator auto_ptr_ref<_Other>() _THROW0()
32 { // convert to compatible auto_ptr_ref
33 _Other *_Cvtptr = _Myptr; // test implicit conversion
34 auto_ptr_ref<_Other> _Ans(_Cvtptr);
35 _Myptr = 0; // pass ownership to auto_ptr_ref
36 return (_Ans);
37 }
38
39
40 template<class _Other>
41 auto_ptr<_Ty>& operator=(auto_ptr<_Other>& _Right) _THROW0()
42 { // assign compatible _Right (assume pointer)
43 reset(_Right.release());
44 return (*this);
45 }
46
47 template<class _Other>
48 auto_ptr(auto_ptr<_Other>& _Right) _THROW0()
49 : _Myptr(_Right.release())
50 { // construct by assuming pointer from _Right
51 }
52
53 auto_ptr<_Ty>& operator=(auto_ptr<_Ty>& _Right) _THROW0()
54 { // assign compatible _Right (assume pointer)
55 reset(_Right.release());
56 return (*this);
57 }
58
59 auto_ptr<_Ty>& operator=(auto_ptr_ref<_Ty> _Right) _THROW0()
60 { // assign compatible _Right._Ref (assume pointer)
61 _Ty *_Ptr = _Right._Ref;
62 _Right._Ref = 0; // release old
63 reset(_Ptr); // set new
64 return (*this);
65 }
66
67 ~auto_ptr()
68 { // destroy the object
69 delete _Myptr;
70 }
71
72 _Ty& operator*() const _THROW0()
73 { // return designated value
74
75 #if _HAS_ITERATOR_DEBUGGING
76 if (_Myptr == 0)
77 _DEBUG_ERROR("auto_ptr not dereferencable");
78 #endif /* _HAS_ITERATOR_DEBUGGING */
79
80 __analysis_assume(_Myptr);
81
82 return (*get());
83 }
84
85 _Ty *operator->() const _THROW0()
86 { // return pointer to class object
87
88 #if _HAS_ITERATOR_DEBUGGING
89 if (_Myptr == 0)
90 _DEBUG_ERROR("auto_ptr not dereferencable");
91 #endif /* _HAS_ITERATOR_DEBUGGING */
92
93 return (get());
94 }
95
96 _Ty *get() const _THROW0()
97 { // return wrapped pointer
98 return (_Myptr);
99 }
100
101 _Ty *release() _THROW0()
102 { // return wrapped pointer and give up ownership
103 _Ty *_Tmp = _Myptr;
104 _Myptr = 0;
105 return (_Tmp);
106 }
107
108 void reset(_Ty* _Ptr = 0)
109 { // destroy designated object and store new pointer
110 if (_Ptr != _Myptr)
111 delete _Myptr;
112 _Myptr = _Ptr;
113 }
114
115 private:
116 _Ty *_Myptr; // the wrapped object pointer
117 };
118 _STD_END

      从上面这个定义就可以看出来,定义个智能指针就相当于创建了一个auto_ptr类的对象。现在我们再来看看这个类的析构函数:

~auto_ptr()
{	// destroy the object
	delete _Myptr;
}

      这里我们就可以看到,由于在私有数据成员中定义了一个模板指针:

_Ty *_Myptr;

      所以说在上面的析构函数里面,当我们删除_Myptr指针的时候,其实就是调用delete删除_Myptr所指向的内存块。所以每当我们定义一个智能指针,就是定义了一个auto_ptr类的对象,如:

auto_ptr<string> p (new string);

      这句话就定义了一个auto_ptr类的对象p,尖括号里面的string用了初始化它的模板成员_Ty的类型。那么这里面,只要auto_ptr对象存在,它指向的字符串就存在,同理,如果auto_ptr对象不存在,会利用auto_ptr类中的析构函数自动销毁它所指向的字符串,也就避免了内存泄露。

      好了,下面我们来用智能指针重写上面的程序,看看会有什么结果。

#include <iostream>
#include <memory>
using namespace std;
class normal_pointer_example
{
public:
	normal_pointer_example(){cout<<"构造函数执行!\n";}
	~normal_pointer_example(){cout<<"析构函数执行!\n";}
};
class normal_pointer_wrong{};//normal_pointer_wrong异常
bool quit;
void quit_func()
{
	if(quit==true)
		cout<<"调用quit_func函数!\n";
	throw normal_pointer_wrong();
}
int main()
{
	try
	{
		auto_ptr<normal_pointer_example> Apointer (new normal_pointer_example);
		quit=true;
		quit_func();
		//delete Npointer;
	}
	catch (normal_pointer_wrong)
	{
		cout<<"输出normal_pointer_wrong异常!!\n";
	}
	return 0;
}

  首先需要注意的是,要调用auto_ptr智能指针,必须包含头文件<memory>。另外,程序的输出:

      看到没有,这样一来,析构函数就执行咯~~

posted @ 2011-08-16 21:46  uniqueliu  阅读(8095)  评论(1编辑  收藏  举报