标签:style blog http color io os ar 使用 for
auto_ptr是当前C++标准库(STL)中提供的一种智能指针,包含头文件 #include<memory> 便可以使用。auto_ptr 能够方便的管理单个堆内存对象,下面贴出SGI中的auto_ptr源码。
1 /*
2 * Copyright (c) 1997-1999
3 * Silicon Graphics Computer Systems, Inc.
4 *
5 * Permission to use, copy, modify, distribute and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appear in all copies and
8 * that both that copyright notice and this permission notice appear
9 * in supporting documentation. Silicon Graphics makes no
10 * representations about the suitability of this software for any
11 * purpose. It is provided "as is" without express or implied warranty.
12 *
13 */
14
15 #ifndef __SGI_STL_MEMORY
16 #define __SGI_STL_MEMORY
17
18 #include <stl_algobase.h>
19 #include <stl_alloc.h>
20 #include <stl_construct.h>
21 #include <stl_tempbuf.h>
22 #include <stl_uninitialized.h>
23 #include <stl_raw_storage_iter.h>
24
25
26 __STL_BEGIN_NAMESPACE
27
28 #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && 29 defined(__STL_MEMBER_TEMPLATES)
30
31 template<class _Tp1> struct auto_ptr_ref {
32 _Tp1* _M_ptr;
33 auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
34 };
35
36 #endif
37
38 template <class _Tp> class auto_ptr {
39 private:
40 _Tp* _M_ptr;
41
42 public:
43 typedef _Tp element_type;
44
45 explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
46 auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
47
48 #ifdef __STL_MEMBER_TEMPLATES
49 template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
50 : _M_ptr(__a.release()) {}
51 #endif /* __STL_MEMBER_TEMPLATES */
52
53 auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
54 if (&__a != this) {
55 delete _M_ptr;
56 _M_ptr = __a.release();
57 }
58 return *this;
59 }
60
61 #ifdef __STL_MEMBER_TEMPLATES
62 template <class _Tp1>
63 auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW {
64 if (__a.get() != this->get()) {
65 delete _M_ptr;
66 _M_ptr = __a.release();
67 }
68 return *this;
69 }
70 #endif /* __STL_MEMBER_TEMPLATES */
71
72 // Note: The C++ standard says there is supposed to be an empty throw
73 // specification here, but omitting it is standard conforming. Its
74 // presence can be detected only if _Tp::~_Tp() throws, but (17.4.3.6/2)
75 // this is prohibited.
76 ~auto_ptr() { delete _M_ptr; }
77
78 _Tp& operator*() const __STL_NOTHROW {
79 return *_M_ptr;
80 }
81 _Tp* operator->() const __STL_NOTHROW {
82 return _M_ptr;
83 }
84 _Tp* get() const __STL_NOTHROW {
85 return _M_ptr;
86 }
87 _Tp* release() __STL_NOTHROW {
88 _Tp* __tmp = _M_ptr;
89 _M_ptr = 0;
90 return __tmp;
91 }
92 void reset(_Tp* __p = 0) __STL_NOTHROW {
93 if (__p != _M_ptr) {
94 delete _M_ptr;
95 _M_ptr = __p;
96 }
97 }
98
99 // According to the C++ standard, these conversions are required. Most
100 // present-day compilers, however, do not enforce that requirement---and,
101 // in fact, most present-day compilers do not support the language
102 // features that these conversions rely on.
103
104 #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && 105 defined(__STL_MEMBER_TEMPLATES)
106
107 public:
108 auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
109 : _M_ptr(__ref._M_ptr) {}
110
111 auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW {
112 if (__ref._M_ptr != this->get()) {
113 delete _M_ptr;
114 _M_ptr = __ref._M_ptr;
115 }
116 return *this;
117 }
118
119 template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW
120 { return auto_ptr_ref<_Tp1>(this->release()); }
121 template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW
122 { return auto_ptr<_Tp1>(this->release()); }
123
124 #endif /* auto ptr conversions && member templates */
125 };
126
127 __STL_END_NAMESPACE
128
129 #endif /* __SGI_STL_MEMORY */
相信对STL有了解的同学对auto_ptr不会陌生,使用起来很方便,目的是为了方便管理堆上创建的指针,防止内存泄露。这里只谈谈源码中一些值得注意的要点:
1 int main()
2 {
3 int* p = new int(12);
4 auto_ptr<int> aptr1(p);
5 auto_ptr<int> aptr2(p);
6
7 return 0;
8 }
上述代码中由于aptr1和aptr2均指向同一块内存p,两个对象析构时会出现同一块内存重复释放的问题,所以应避免上述编码方式。
1 int main()
2 {
3 int* p = new int(12);
4 auto_ptr<int> aptr1(p);
5 auto_ptr<int> aptr2(aptr1);
6 cout<<*aptr1<<endl;
7
8 return 0;
9 }
上述代码中line6,输出*aptr1时,会出现undefine行为,因为在构造aptr2时,aptr1中原生指针已经被赋值为NULL。这种情况会更隐蔽的出现在函数调用传参或者返回时:
1 void foo(auto_ptr<int> ap)
2 {
3 cout<<*ap<<endl;
4 return;
5 }
6
7 int main()
8 {
9 auto_ptr<int> scope(new int(12));
10 foo(scope);
11 cout<<*scope<<endl;
12
13 return 0;
14 }
1 class Person
2 {
3 public:
4 virtual void action()const = 0;
5 };
6 class Student : public Person
7 {
8 public:
9 virtual void action()const
10 {
11 cout<<"Student action"<<endl;
12 }
13 };
14 class Teacher : public Person
15 {
16 public:
17 virtual void action()const
18 {
19 cout<<"Teacher action"<<endl;
20 }
21 };
22
23 void raw_action(const Person *p)
24 {
25 p->action();
26 }
27
28 void apt_action(auto_ptr<Person> apt)
29 {
30 apt->action();
31 }
32
33 int main()
34 {
35 Student * pStu = new Student;
36 Teacher * pTea = new Teacher;
37 raw_action(pStu);
38 raw_action(pTea);
39
40 auto_ptr<Student> apStu(pStu);
41 auto_ptr<Teacher> apTea(pTea);
42
43 //这里如果直接调用会出现二义性,有多个从auto_ptr<Derived>到auto_ptr<Base>的转换:构造函数和operator转换操作符
44 //apt_action(apStu);
45 //apt_action(apTea)
46 auto_ptr<Person> ap1(apStu);
47 auto_ptr<Person> ap2(apTea);
48
49 apt_action(ap1);
50 apt_action(ap2);
51
52 return 0;
53 }
代码中使用原生指针可以轻松实现多态,而对于auto_ptr,auto_ptr<Person>与auto_ptr<Student>和auto_ptr<Teacher>本不构成继承体系,由于有了成员模板函数才使得它们能够完成有派生类向基类的转换。
1 auto_ptr<int> fun()
2 {
3 return auto_ptr<int>(new int(12));
4 }
5
6 int main()
7 {
8 auto_ptr<int> ap1 = auto_ptr<int>(new int(12));//用一个临时变量进行赋值初始化
9
10 auto_ptr<int> ap2 (fun());//调用fun()返回一个临时auto_ptr进行初始化
11
12 return 0;
13 }
由于auto_ptr的控制复制函数入参类型都是非const的,而临时对象只能绑定在const &或者具体类型上,而对于第一句会调用auto_ptr的拷贝构造函数,但是拷贝构造函数入参是一个非const引用,无法将临时对象绑定在非const引用上,所以编译不会通过;对于fun()函数返回的auto_ptr对象,同样会调用拷贝构造,而此时的临时对象同样无法绑定在非const引用上。auto_ptr_ref的引入就是为了解决这个问题。具体来说,auto_ptr<int> ap1 = auto_ptr<int>(new int(12)); 首先创建了一个原生指针指向12的auto_ptr的临时对象,根据
1 template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW
2 { return auto_ptr_ref<_Tp1>(this->release()); }
1 auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
2 : _M_ptr(__ref._M_ptr) {}
此构造函数的入参时值类型 auto_ptr_ref<_Tp> __ref 不是引用,而是值传递,所以临时对象(右值)可以进行绑定,auto_ptr_ref<_Tp>先调用默认生成的拷贝构造函数,生成入参 __ref,在 _M_ptr(__ref._M_ptr)之后临时对象析构。
auto_ptr是C++标准中功能最简单的智能指针,主要为了解决资源泄漏的问题。它的实现原理其实是RAII,在构造的时候获取资源,在析构的时候释放资源,从源码中看出实现有很多巧妙之处。上面提到了一些auto_ptr的不足之处,可以使用更高级的带有引用计数的智能指针来代替。标签:style blog http color io os ar 使用 for
原文地址:http://www.cnblogs.com/Tour/p/4036493.html