Weak pointer的实现方法.


  1#include <assert.h>
  2#include <map>
  3#include <stdio.h>
  4
  5// memory leak checker
  6struct Value
  7{
  8    bool valid;
  9    int line;
 10
 11    Value()
 12    :valid(false), line(-1)
 13    {}
 14
 15    Value(bool v, int l)
 16        :valid(v), line(l)
 17    {
 18    }

 19}
;
 20
 21typedef std::map<void*, Value> ContainerType;
 22ContainerType myMap;
 23
 24#define mynew(x) mynew_(x, __LINE__)
 25
 26void checkMemory()
 27{
 28    size_t n = myMap.size();
 29    //assert(n==0);
 30
 31    if(n>0)
 32    {
 33        printf("Memory leak found:\n");
 34        for (ContainerType::const_iterator it=myMap.begin();
 35            it!=myMap.end();++it)
 36        {
 37            printf("Line %d\n", it->second.line);
 38        }

 39        assert(0);
 40    }

 41}

 42
 43template <class T>
 44T* mynew_(T const &n, int line)
 45{
 46    T* p = (T*)malloc(sizeof(T));
 47    *= n;
 48    myMap[p]=Value(true, line);
 49    return p;
 50}

 51
 52void mydelete(void* p)
 53{
 54    ContainerType::iterator it = myMap.find(p);
 55    assert(it!=myMap.end());
 56    myMap.erase(it);
 57    free(p);
 58}

 59
 60class AutoPtr
 61{
 62public:
 63    explicit AutoPtr(int *p=0)
 64    :p_(p), refCnt_(mynew(int(1))), valid_(mynew(bool(p?true:false)))
 65    {}
 66
 67    ~AutoPtr()
 68    {
 69        if(p_)
 70        {
 71            mydelete (p_);
 72        }

 73
 74        (*refCnt_)--;
 75        
 76        *valid_ = false;
 77
 78        assert(*refCnt_>=0);
 79        if(*refCnt_==0)
 80        {
 81            mydelete(refCnt_);
 82            mydelete(valid_);
 83        }

 84    }

 85
 86    bool empty() const
 87    {
 88        if(!*valid_) 
 89            assert(p_==0);
 90        else
 91            assert(p_!=0);
 92
 93        return !(*valid_);
 94    }

 95private:
 96    friend class WeakPtr;
 97    AutoPtr(const AutoPtr&);
 98    AutoPtr& operator =(const AutoPtr&);
 99
100    int *p_;
101    bool *valid_;
102    int *refCnt_;    //weak ref cnt, always valid if one weakPtr or AutoPtr exist
103}
;
104
105class WeakPtr
106{
107public:
108    // ctor
109    WeakPtr()
110    :p_(0), refCnt_(mynew(int(1))), valid_(mynew(bool(false)))
111    {
112    }

113
114    explicit WeakPtr(AutoPtr& p)    //p must be valid
115    :p_(&p), refCnt_(p.refCnt_),valid_(p.valid_)
116    {
117        (*p_->refCnt_)++;
118    }

119    
120    WeakPtr(const WeakPtr& rhs)    //p must be valid
121    {
122        construct(rhs);
123    }

124
125    ~WeakPtr()
126    {
127        destroy();
128    }

129
130    // get
131    bool empty() const
132    {
133        assert((*refCnt_)>=0);
134        return !(*valid_);
135    }

136
137    // operator    
138    WeakPtr& operator=(const WeakPtr &rhs)
139    {
140        if(this!=&rhs)
141        {
142            destroy();
143            construct(rhs);
144        }

145        return *this;
146    }

147
148private:
149    void destroy()
150    {
151        (*refCnt_)--;
152
153        assert((*refCnt_)>=0);
154        if(0==*refCnt_)
155        {
156            mydelete(refCnt_);
157            mydelete(valid_);
158        }

159    
160    }

161    void construct(const WeakPtr &rhs)
162    {
163        p_ = rhs.p_;
164        refCnt_ = rhs.refCnt_;
165        valid_ = rhs.valid_;
166        (*refCnt_)++;
167    }

168
169    AutoPtr *p_;
170    bool *valid_;
171    int *refCnt_;    //weak ref cnt, always valid if one weakPtr or AutoPtr exist
172}
;
173
174void Test()
175{
176    WeakPtr p1;
177
178    assert(p1.empty());
179    {
180        AutoPtr p(mynew(int(100)));
181        p1 = WeakPtr(p);
182        assert(!p1.empty());
183        assert(!p.empty());
184    }

185    assert(p1.empty());
186
187    //mynew(int());
188}

189
190void main()
191{
192    Test();
193    checkMemory();
194}

Powered by Jekyll and Theme by solid

本站总访问量