C++ - 基于引用计数的基本垃圾回收器

3
好的,我正在尝试使用引用计数的概念在C++中实现一个垃圾收集器(一个非常基本的垃圾收集器),它可以工作,但是有些地方我不理解。
我有两个类:
  • 一个名为GC的类,基本上它只是增加和减少引用计数
  • 一个名为TObject的类,它扮演智能指针的角色(我重载了*和->运算符,以及=运算符)
  • 下面是代码:GC.cpp
    #include <iostream>
    
    using namespace std;
    
    class GC {
    public:
        GC(){
            this->refCount = 0;//Initialisation du compteur à zero
        }
    
        void incrementRef(){
            this->refCount++;//Incrémentation du compteur de references
        }
    
        int decrementRef(){
            return this->refCount--;//Décrementation du compteur de references
        }
    
        int getCounter(){//Getter du compteur de references
            return refCount;
        }
        ~GC(){}
    
    private:
        int refCount; //Compteur de references
    };
    

    TObject.cpp:

    #include <iostream>
    #include "GC.cpp"
    
    using namespace std;
    
    template <class T>
    class TObject {
    
    T *p;
    GC *gc;
    
    public:
        TObject(T *p){
            cout<<"refobject"<<endl;
            this->p = p;
            gc = new GC();
            this->gc->incrementRef();
        }
    
        virtual ~TObject(){//Destructeur
            cout<<"delete TObject"<<endl;
            if(this->gc->decrementRef() == 0){
                delete p;
                delete gc;
            }
        }
    
        T* operator->(){//Surcharge de l'opérateur d'indirection
            return p;
        }
    
        T& operator*() const {//Surchage de l'opérateur
            return *p;
        }
    
        TObject<T>& operator=(const TObject<T> &t){
            if(this->gc->decrementRef() == 0){
                delete p;
                delete gc;
            }
            this->p = t.p;
            this->gc = t.gc;
            this->gc->incrementRef();
            return *this;
        }
    
        GC getGC(){
            return *gc;
        }
    };
    

    这是我在主函数中测试它的方法:
    TObject<int> t(new int(2));
    cout<<"t1 counter: "<<t.getGC().getCounter()<<endl;//Displays 1
    TObject<int> t2(NULL);
    cout<<"t2 counter: "<<t2.getGC().getCounter()<<endl;//Displays 1
    t2 = t;
    cout<<"t1 counter: "<<t.getGC().getCounter()<<endl;//Displays 2, why?
    cout<<"t2 counter: "<<t2.getGC().getCounter()<<endl;//Displays 2
    

    我不明白,我把t复制到t2中,并没有更新t1!为什么它的引用计数也被更新了?

    1
    你是否知道我们已经有了std::shared_ptr来进行引用计数的内存/生命周期管理? - Baum mit Augen
    是的,但只是想知道它是如何工作的。 - Chandler Bing
    你需要阅读Eric Lippert的如何调试小程序来自己回答这个问题。 - Martin Bonner supports Monica
    你的TObject类需要一个复制构造函数,以及赋值运算符(请阅读“三法则”)。你的赋值运算符应该使用“拷贝并交换” - 这可以避免当你意外地将一个对象分配给它本身时出现问题。它还使异常安全更容易实现。 - Martin Bonner supports Monica
    1个回答

    2
    这是因为t和t2共享同一个gc实例。看一下你重载的=运算符方法:
    TObject<T>& operator=(const TObject<T> &t)
    {
       if(this->gc->decrementRef() == 0)
       {
            delete p;
            delete gc;
       }
       this->p = t.p;
       this->gc = t.gc;  // you are using same gc. Instead, you must be using
                         //  this->gc = new GC(); 
       this->gc->incrementRef();
       return *this;
    }
    

    是的,你说得对,谢谢! 那么,你觉得这个程序怎么样?它正确吗? - Chandler Bing
    实际上,根据你所实现的gc方式,我认为当t2被赋值给t时,你必须期望2作为引用计数。无论如何,我已经为你提供了解决方案,关于你为什么会得到2个? - Mangu Singh Rajpurohit
    是的,那就是解决方案,但我考虑了一下,意识到我应该传递相同的垃圾收集器,因为它们都指向同一个对象! - Chandler Bing
    没错。这就是像Python、Java等高级语言中实现垃圾回收的方式。 - Mangu Singh Rajpurohit

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接