2011年6月19日日曜日

shared_ptr を自分で書いてみる 3

参照カウントと削除子の二つ分もメモリ確保してるのはちょっと勿体ないなぁ というか,よく考えてみると,この二つは同じ寿命なので一つにまとめても 良さそうです.

ということで参照カウントと削除子を両方管理するような shared_count クラスを用意してみたバージョンがこんな感じ.

struct shared_count
{
    long count_;

    shared_count() :count_(1) {}
    void increment() { ++count_; }
    void decrement(void* p)
    {
        if (--count_ == 0) {
            release(p);
            delete this;
        }
    }
    virtual void release(void*) const = 0;
};
    
template <typename T> struct shared_count_default :public shared_count
{
    virtual void release(void* p) const
    {
        delete reinterpret_cast<T*>(p);
    }
};

template <typename T> class shared_ptr
{
    T* ptr_;
    shared_count* count_;
        
public:
    typedef T element_type;
        
    shared_ptr() :ptr_(0), count_(0) {}
    ~shared_ptr()
    {
        if (count_) { count_->decrement(ptr_); }
    }
        
    template <typename Y> explicit shared_ptr(Y* p)
        :ptr_(p), count_(new shared_count_default<Y>)
    {
    }

    shared_ptr(const shared_ptr& r) :ptr_(r.ptr_), count_(r.count_)
    {
        if (count_) {
            count_->increment();
        }
    }
    
    shared_ptr& operator = (const shared_ptr& r)
    {
        if (count_ != r.count_) {
            shared_ptr(r).swap(*this);
        }
        return *this;
    }
        
    T& operator * () const { return *ptr_;}
    T* operator -> () const { return ptr_; }
    
    long use_count() const { return count_ ? count_->count_ : 0; }
    T* get() const { return ptr_; }
    
    void swap(shared_ptr& r)
    {
        std::swap(ptr_, r.ptr_);
        std::swap(count_, r.count_);
    }
    void reset()
    {
        shared_ptr().swap(*this);
    }
};

意味的に increment, decrement の処理は shared_count 側だろう思っ て移しましたけど,そうすると decrement にポインタを渡さないといけな くなってしまい,これはこれでちょっと意味が変な気もします.モヤモヤ

0 件のコメント:

コメントを投稿