思考:

  使用智能指针替换单链表LinkLIst中的原生指针是否可行?

将LinkList.h中的Node指针全部改成智能指针:

  1 #ifndef LINKLIST_H
  2 #define LINKLIST_H
  3 
  4 #include "List.h"
  5 #include "Exception.h"
  6 #include "SmartPointer.h"
  7 
  8 namespace DTLib
  9 {
 10 
 11 template < typename T >
 12 class LinkList : public List<T>
 13 {
 14 protected:
 15     struct Node : public Object
 16     {
 17         T value;
 18         SmartPointer<Node> next;
 19     };
 20 
 21     mutable struct : public Object
 22     {
 23         char reserved[sizeof(T)];
 24         SmartPointer<Node> next;
 25     }m_header;
 26 
 27     int m_length;
 28     int m_step;
 29     SmartPointer<Node> m_current;
 30 
 31     Node* position(int i) const    //  O(n)
 32     {
 33         //Node* ret = reinterpret_cast<Node*>(&m_header);
 34         SmartPointer<Node> ret = reinterpret_cast<Node*>(&m_header);
 35 
 36         for(int p = 0; p < i; p++)
 37         {
 38             ret = ret->next;
 39         }
 40 
 41         return ret.get();
 42     }
 43 
 44     virtual Node* create()
 45     {
 46         return new Node();
 47     }
 48 
 49     virtual void destroy(Node* pn)
 50     {
 51         delete pn;
 52     }
 53 
 54 public:
 55     LinkList()
 56     {
 57         m_header.next = NULL;
 58         m_length = 0;
 59         m_step = 1;
 60         m_current = NULL;
 61     }
 62 
 63     bool insert(const T& e)
 64     {
 65         return insert(m_length, e);
 66     }
 67 
 68     bool insert(int i, const T& e)   // O(n)
 69     {
 70         bool ret = ((0 <= i) && (i <= m_length));
 71 
 72         if( ret )
 73         {
 74             Node* node = create();
 75 
 76             if( node != NULL )
 77             {
 78                 Node* current = position(i);
 79 
 80                 node->value = e;
 81                 node->next = current->next;
 82                 current->next = node;
 83 
 84                 m_length++;
 85             }
 86             else
 87             {
 88                 THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element...");
 89             }
 90         }
 91 
 92         return ret;
 93     }
 94 
 95     bool remove(int i)   // O(n)
 96     {
 97         bool ret = ((0 <= i) && (i < m_length));
 98 
 99         if( ret )
100         {
101             SmartPointer<Node> current = position(i);
102 
103             SmartPointer<Node> toDel = current->next;
104 
105             if( m_current == toDel )
106             {
107                 m_current = toDel->next;
108             }
109 
110             current->next = toDel->next;
111 
112             m_length--;
113 
114             // destroy(toDel);
115 
116         }
117 
118         return ret;
119     }
120 
121     bool set(int i, const T& e)   //  O(n)
122     {
123         bool ret = ((0 <= i) && (i < m_length));
124 
125         if( ret )
126         {
127             position(i)->next->value = e;
128         }
129 
130         return ret;
131     }
132 
133     T get(int i) const
134     {
135         T ret;
136 
137         if( get(i, ret) )
138         {
139             return ret;
140         }
141         else
142         {
143             THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
144         }
145 
146         return ret;
147     }
148 
149     bool get(int i, T& e) const    // O(n)
150     {
151         bool ret = ((0 <= i) && (i < m_length));
152 
153         if( ret )
154         {
155             e = position(i)->next->value;
156         }
157 
158         return ret;
159     }
160 
161     int find(const T& e) const    //  O(n)
162     {
163         int ret = -1;
164         int i = 0;
165 
166         SmartPointer<Node> node = m_header.next;
167 
168         //while( node )
169         while( node.isNull() )
170         {
171             if( node->value == e )
172             {
173                 ret = i;
174                 break;
175             }
176             else
177             {
178                 node = node->next;
179                 i++;
180             }
181         }
182 
183         return ret;
184     }
185 
186     int length() const   // O(1)
187     {
188         return m_length;
189     }
190 
191     void clear()    //  O(n)
192     {
193         //while( m_header.next )
194         while( m_header.next.isNull() )
195         {
196             //Node* toDel = m_header.next;
197             SmartPointer<Node> toDel = m_header.next;
198 
199             m_header.next = toDel->next;
200 
201             m_length--;
202 
203             // destroy(toDel);
204         }
205 
206         // m_length = 0;
207     }
208 
209     bool move(int i, int step = 1)
210     {
211         bool ret = (0 <= i) && (i < m_length) && (step > 0);
212 
213         if( ret )
214         {
215             m_current = position(i)->next;
216             m_step = step;
217         }
218 
219         return ret;
220     }
221 
222     bool end()
223     {
224         //return (m_current == NULL);
225         return m_current.isNull();
226     }
227 
228     T current()
229     {
230         if( !end() )
231         {
232             return m_current->value;
233         }
234         else
235         {
236             THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
237         }
238     }
239 
240     bool next()   //每次移动step步
241     {
242         int i = 0;
243 
244         while((i < m_step) && !end())
245         {
246             m_current = m_current->next;
247             i++;
248         }
249 
250         return (i == m_step);
251     }
252 
253     ~LinkList()   //  O(n)
254     {
255         clear();
256     }
257 };
258 
259 }
260 
261 #endif // LINKLIST_H

测试程序如下:

 1 #include <iostream>
 2 #include "LinkList.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 
 8 int main()
 9 {
10     LinkList<int> list;
11 
12     for(int i = 0; i < list.length(); i++)
13     {
14         list.insert(i);
15     }
16 
17     for(list.move(0); !list.end(); list.next())
18     {
19         cout << list.current() << endl;
20     }
21 
22     return 0;
23 }

运行结果如下:

程序直接崩溃了。

 

 我们的SmartPointer设计中,一片堆空间最多只能由一个指针标识,但是我们设计的和遍历有关的函数,例如move、end、current、next,在遍历时一片堆空间会由多个指针指向,所以程序崩溃了。

改进方案:

我们需要创建一个中间类pointer,并且它还有两个子类。

SharedPointer支持一片堆空间由多个指针指向,也支持自动释放。

在设计上做了改动,所以SmartPointer也得做改动。

pointer类中的析构函数是纯虚函数,因为pointer是一个抽象父类,需要由子类继承才能生成对象。

Object的析构函数就是纯虚的,所以pointer中就没有必要再写一遍了。

只要pointer没有实现自己的析构函数,那么它就还是一个抽象类。

添加Pointer.h文件,内容如下:

 1 #ifndef POINTER_H
 2 #define POINTER_H
 3 
 4 #include "Object.h"
 5 
 6 namespace DTLib
 7 {
 8 
 9 template < typename T >
10 class Pointer : public Object
11 {
12 protected:
13     T* m_pointer;
14 
15 public:
16     Pointer(T* p = NULL)
17     {
18         m_pointer = p;
19     }
20 
21     T* operator->()
22     {
23         return m_pointer;
24     }
25 
26     T& operator* ()
27     {
28         return *m_pointer;
29     }
30 
31     bool isNull()
32     {
33         return (m_pointer == NULL);
34     }
35 
36     T* get()
37     {
38         return m_pointer;
39     }
40 
41     // 不需要析构函数,这里继承自Object,只要不实现具体的析构函数,这个类就是抽象类
42 };
43 
44 }
45 
46 #endif // POINTER_H

SmartPointer.h的内容更改如下:

 1 #ifndef SMARTPOINTER_H
 2 #define SMARTPOINTER_H
 3 
 4 #include "Pointer.h"
 5 
 6 namespace DTLib
 7 {
 8 
 9 template <typename T>
10 class SmartPointer : public Pointer<T>
11 {
12 public:
13     SmartPointer(T *p = NULL) : Pointer<T>(p)
14     {
15 
16     }
17 
18     SmartPointer(const SmartPointer<T>& obj)
19     {
20         this->m_pointer = obj.m_pointer;
21 
22         const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;
23     }
24 
25     SmartPointer<T>& operator= (const SmartPointer<T>& obj)
26     {
27         if(this != &obj)
28         {
29             T* p = this->m_pointer;
30 
31             this->m_pointer = obj.m_pointer;
32 
33             const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;
34 
35             delete p;
36         }
37 
38         return *this;
39     }
40 
41     ~SmartPointer()   // 肯定需要这个析构函数,否则还是抽象类
42     {
43         delete this->m_pointer;
44     }
45 };
46 
47 }
48 
49 #endif // SMARTPOINTER_H

第25-36行的赋值操作符改成了异常安全的,将delete操作放到了最后。

SmartPointer.h中删掉了一些重载函数,放到了Pointer.h中,SmartPointer继承自Pointer。

测试程序如下:

 1 #include <iostream>
 2 #include "SmartPointer.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 
 8 class Test : public Object
 9 {
10 public:
11     Test()
12     {
13         cout << "Test()" << endl;
14     }
15 
16     ~Test()
17     {
18         cout << "~Test()" << endl;
19     }
20 };
21 
22 int main()
23 {
24     SmartPointer<Test> sp = new Test();
25 
26     return 0;
27 }

结果如下:

可以看到自动调用了Test的析构函数。

 

思考:

 

posted on 2018-09-15 20:51  周伯通789  阅读(351)  评论(0编辑  收藏  举报