【问题标题】:C++ - Basic garbage collector using reference countingC++ - 使用引用计数的基本垃圾收集器
【发布时间】:2016-11-05 20:51:48
【问题描述】:

好的,我正在尝试使用引用计数的概念在 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;
        }
    };
    

    这里是我如何在 main 中测试它的:

    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
    

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

    【问题讨论】:

    • 您知道我们已经有std::shared_ptr 用于引用计数内存/生命周期管理吗?
    • 是的,但只是想知道它是如何工作的
    • 您需要阅读 Eric Lippert 的[如何调试小程序]{ericlippert.com/2014/03/05/how-to-debug-small-programs) 自行回答。
    • 您的 TObject 类需要一个复制构造函数以及赋值(阅读“3 规则”)。您的赋值运算符应该使用“复制和交换” - 它可以避免在将对象分配给自身时出现问题(通常是偶然的)。它还使异常安全更容易。

    标签: c++ garbage-collection smart-pointers reference-counting


    【解决方案1】:

    这是因为 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;
    }
    

    【讨论】:

    • 是的,你是对的,谢谢!而且,你觉得这个节目怎么样?对吗?
    • 实际上,你实现 gc 的方式,我想你一定期望 2 作为引用计数,当 t2 被分配 t 时。无论如何,我已经给你解决了你为什么得到 2 的解决方案?
    • 是的,这就是解决方案,但我想了想,我意识到我应该通过相同的 gc,因为它们都指向同一个对象!
    • 正确。这就是 gc 在 python、java 等高级语言中的实现方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 2021-05-25
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多