《C++编程艺术》第二章的垃圾回收器 源码Bug修改

时间:2023-02-11 20:09:08

《C++编程艺术》上第二章的代码运行第一个测试程序的时候就报错了,上网找了下,没找到具体的解决方法,CSDN上有网友说是在collect里面出的错。

 好吧,我自己动手调进去修改吧。

#include <iostream> 
#include <new> 
#include "gc.h" 

using namespace std; 

int main() { 
    GCPtr<int> p; 

    try { 
        p = new int; 
    } catch(bad_alloc exc) { 
        cout << "Allocation failure!\n"; 
        return 1; 
    } 

    *p = 88; 

    cout << "Value at p is: " << *p << endl; 

    int k = *p; 

    cout << "k is " << k << endl; 

    system("pause");

    return 0; 
}


在这个函数上单步调试了下,发现到最后return 0那步才引起的中断,看来确实是collect函数出的错。

 1 template <class T, int size>  
 2 bool GCPtr<T, size>::collect() {    
 3     bool memfreed = false;        //是否有内存被释放的标记
 4 
 5 #ifdef DISPLAY   
 6     cout << "Before garbage collection for ";   
 7     showlist();   
 8 #endif   
 9 
10     list<GCInfo<T> >::iterator p;  
11     //这里用两层循环,每次释放了内存后,都要从头对gclist进行再次搜索 
12     do {   
13 
14         // 扫描gclist查找是否有refcount为0的条目,当找到这种条目时
15         // 调用remove函数删除它,remove是STL list类的一个成员
16         for(p = gclist.begin(); p != gclist.end(); p++) {   
17             if(p->refcount > 0) 
18                 continue;   
19 
20             memfreed = true;   
21 
22 
23 
24             // 释放空指向的内存地址 
25             if(p->memPtr) { 
26                 if(p->isArray) {   
27 #ifdef DISPLAY   
28                     cout << "Deleting array of size "   
29                         << p->arraySize << endl;   
30 #endif   
31                     delete[] p->memPtr;    // 释放数组  
32                 }   
33                 else {   
34 #ifdef DISPLAY   
35                     cout << "Deleting: "   
36                         << *(T *) p->memPtr << "\n";   
37 #endif   
38                     delete p->memPtr;        // 释放当个对象 
39                 }   
40 
41             } 
42             // 从gclist中删除空指向的条目. 
43             gclist.remove(*p);   
44 
45             // 重新搜索
46             break; 
47         } 
48 
49     } while(p != gclist.end());   
50 
51 #ifdef DISPLAY   
52     cout << "After garbage collection for ";   
53     showlist();   
54 #endif   
55 
56     return memfreed;   
57 }   


注:上面是修改好的代码

进collect函数后发现,执行gclist.remove(*p);  这步后,后面的p->refcount,p->isArray等信息全错了,突然醒悟过来,

因为这步释放了p节点,而后面还要读取p节点的相关信息,因此导致错误发生。正确的做法是先对p节点进行读取refcount,

isArray等信息,然后释放p中的memptr指针,最后对p节点进行释放。修改好的代码如上所示。