第二十六课 典型问题分析(Bugfix)

问题1:

glibc中的strdup实现如下:

没有对参数s进行空指针判断。

我们的Exception.cpp中应做改进:

在第12行进行判断空指针操作。

 问题2:

t1在析构时会抛出异常,我们在remove一个对象时,要保证链表还是合法的,也就是保证异常安全性。

如上图,我们期望打印的链表长度为2。

示例程序:

 1 #include <iostream>
 2 #include "LinkList.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 class Test : public Object
 8 {
 9     int m_id;
10 public:
11     Test(int id = 0)
12     {
13         m_id = id;
14     }
15 
16     ~Test()
17     {
18         if( m_id == 1 )
19         {
20             throw m_id;
21         }
22     }
23 };
24 
25 int main()
26 {
27     LinkList<Test> list;
28     Test t0(0), t1(1), t2(2);
29 
30     try
31     {
32         list.insert(t0);
33         list.insert(t1);
34         list.insert(t2);
35 
36         list.remove(1);
37     }
38     catch(int e)
39     {
40         cout << e << endl;
41         cout << list.length() << endl;
42     }
43 
44     return 0;
45 }

结果如下:

程序直接崩溃了。

vc下的运行结果如下:

打印e的值为1,链表长度为3,意味着单链表的状态出问题了。

我们的remove函数没有考虑异常安全性。

修改LinkList.h:

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

在remove函数中,先让m_length--,再做摧毁节点的操作。

在clear函数中,注释掉原来的196行,添加第191行,每次摧毁前让m_length--。

猜你喜欢

转载自www.cnblogs.com/wanmeishenghuo/p/9651435.html