2010-12-30 13 views
12

読んで「C++標準ライブラリを超えては:はじめにブーストする」、私は非常に興味深い例だ:boost ::〜shared_ptrはどのように動作しますか?

class A 
{ 
public: 
    virtual void sing()=0; 
protected: 
    virtual ~A() {}; 
}; 

class B : public A 
{ 
public: 
    virtual void sing() 
    { 
     std::cout << "Do re mi fa so la"<<std::endl;; 
    } 
}; 

をし、私はいくつかのテストを実行します。私はここに非常に好奇心何

int main() 
{ 

//1 
std::auto_ptr<A> a(new B); //will not compile ,error: ‘virtual A::~A()’ is protected 

//2 
A *pa = new B; 
delete pa; //will not compile ,error: ‘virtual A::~A()’ is protected 
delete (dynamic_cast<B*>(pa)); //ok 

//3 
boost::shared_ptr<A> a(new B);//ok 

} 

shared_ptrはどのように動作しますか? 派生クラスBを推論する方法は?

ありがとうございました!

  1. テンプレート構造機能
  2. リソースが〜shared_ptrのでは削除されていない、それを:

    おかげで、すべて、 私は鍵がある

    class sp_counted_base 
    { 
    public: 
        virtual ~sp_counted_base(){} 
    }; 
    
    template<typename T> 
    class sp_counted_base_impl : public sp_counted_base 
    { 
    public: 
        sp_counted_base_impl(T *t):t_(t){} 
        ~sp_counted_base_impl(){delete t_;} 
    private: 
        T *t_; 
    }; 
    
    
    class shared_count 
    { 
    public: 
        static int count_; 
        template<typename T> 
        shared_count(T *t): 
         t_(new sp_counted_base_impl<T>(t)) 
        { 
         count_ ++; 
        } 
        void release() 
        { 
         --count_; 
         if(0 == count_) delete t_; 
        } 
        ~shared_count() 
        { 
         release(); 
        } 
    private: 
        sp_counted_base *t_; 
    }; 
    int shared_count::count_(0); 
    
    template<typename T> 
    class myautoptr 
    { 
    public: 
        template<typename Y> 
        myautoptr(Y* y):sc_(y),t_(y){} 
        ~myautoptr(){ sc_.release();} 
    private: 
        shared_count sc_; 
        T *t_; 
    }; 
    
    int main() 
    { 
        myautoptr<A> a(new B); 
    } 
    

    をどのように動作するか〜shared_ptrのについての簡単なサンプルを作成しますshared_countによって削除されました

答えて

10

驚くべきことに、ここの鍵はboost::shared_ptrデストラクタではなく、そのコンストラクタです。

あなたはboost/shared_ptr.hppに見れば、あなたはshared_ptr<T>「は単に」T *が、期待してコンストラクタがないことがわかります:あなたはB *からboost::shared_ptrを構築する際//3

template<class Y> 
explicit shared_ptr(Y * p); 

を、A *への変換なし実際にBタイプでshared_ptr内部が構築されています。オブジェクトが破棄されると、削除されるのはBポインタです(基本クラスポインタではありません)。

+1

技術的に言えば、B *からA *への変換を実行します。その後のポインターへのすべてのアクセスは、タイプA *を使用します。タイプBの操作は、標準的な多態性を介して行われます(A *を通過します)。唯一の例外は、デストラクタであり、shared_ptrはその "deleter"メカニズム(またはその一般化)を介して覚えている。 – nobar

3

shared_ptrクラステンプレートには、クラスタイプshared_countのメンバがあり、クラスsp_counted_baseへのポインタ型のメンバを持っています。クラスshared_countのコンストラクターテンプレートは、クラステンプレートsp_counted_impl_pのインスタンスへのポインターを、このメンバーに割り当てます。このメンバーは、shared_ptr::value_typeではなく、コンストラクター引数の型によってテンプレート化されています。 sp_counted_baseは、純粋な仮想メンバ関数disposeを持ち、sp_counted_impl_pによって上書きされます。 sp_counted_impl_pはあなたの例ではBの型を知っているので、基本クラスのデストラクタにアクセスすることなく削除することができます。また、仮想ディスパッチを使用するため、実行時に型が決定されます。この方法は、パラメトリックおよびサブタイプ多型の組み合わせを必要とする。

関連する問題