6

shared_ptrを使用してテストを行いましたが、以下の問題を理解することはできません。Boostライブラリを学び始めたところです。理由を教えてくれる人はいますか?

#include <boost\shared_ptr.hpp>
#include <iostream>

class A 
{
public:  
    virtual void sing()
    {
        std::cout<<"A";
    }
protected:  virtual ~A() {};

};

class B : public A 
{
public:  
    virtual void sing() 
    {   
        std::cout << "B"; 
    }
    virtual ~B() {};
};


int foo()
{   
    boost::shared_ptr<A> pa(new B());
    pa->sing();

    delete static_cast<B*>(pa.get());

    delete pa.get(); //this line has a problem error C2248: “A::~A”: can't access protected memmber(declared in class“A")   
    return 0;
}

int main()
{
    foo();
    return 0;
}

ただし、その行がコメント化されている場合はコンパイルできます。確かに、shared_ptrが、私が行ったように、main関数から内部的に維持されているポインターを削除するという意味ではありません。pa.get()によって返されるポインターと内部的に維持されるポインターの間に違いはありますか?

4

4 に答える 4

3

これは、コンストラクターに渡されたポインターのタイプのonのdelete破棄中に呼び出されると思います。shared_ptrここでコンストラクターを見てください:

http://www.boost.org/doc/libs/1_49_0/libs/smart_ptr/shared_ptr.htm#constructors

したがってpa、スコープ外にB::~B( )なると、含まれているタイプのデストラクタではなく、が呼び出されます- A::~A(宣言されているため不可能ですprotected)。

于 2012-05-01T11:23:25.123 に答える
2

実際、それはそれよりも少し複雑です。背後にある機械shared_ptrは非常に複雑です。

まず、以下に特定のアクセス権が付与されていないことを証明しましょうshared_ptr

int main() {
    A* a = new B();
    std::shared_ptr<A> p(a); // expected-error
}

のデストラクタにアクセスできないため、エラーが発生しAます。興味深いことに、エラーは構築の時点で発生します。これが手がかりです...

それで、背後にある魔法は何shared_ptrですか?

内部的には、shared_ptrは単純なポインタと参照の数以上のものを保持します。Aは、オブジェクトのインスタンスの破棄を担当shared_ptrする、で構築されます。deleterデザインが本当に優れているのは、これdeleterがコンストラクターでインスタンス化されるため、ベアshared_ptrタイプが許可するよりも多くのタイプ情報を知っている可能性があることです。

簡略化されたデモ:

template <typename T>
struct shared_holder {
    typedef void (*Disposer)(T*);

    explicit shared_holder_base(T* t, Disposer d): _ptr(t), _disposer(d) {}

    void dispose() { _disposer(_ptr); _ptr = 0; }

    T* _ptr;
    Disposer _disposer;
};

template <typename U, typename T>
void dispose(T* t) { delete static_cast<U*>(t); }

template <typename T>
class shared_ptr {
    typedef shared_holder<T> holder;
public:
    shared_ptr(): _holder(0), _ptr(0) {}

    template <typename U>
    explicit shared_ptr(U* u):
        _holder(new holder(u, dispose<U, T>)), _ptr(_holder->_ptr) {}

private:
    holder* _holder;
    T* _ptr;
};

重要な洞察は、ディスポーザーがコンストラクターによって認識されている静的型からインスタンス化されることです。これが理由です:

  • shared_ptr<A>(new B)作品
  • A* a = new B; shared_ptr<A>(a)ではない

Boostヘッダーを読むことができますが、その背後にある機構shared_ptrは非常に興味深いものです。

読者のための演習として、なぜメンバーshared_ptr<T>がいるのですか?_ptr

于 2012-05-01T13:56:24.387 に答える
1

あなたが持っているとき:

boost::shared_ptr<A> pa(new B());

...boost::shared_ptrコンストラクターを呼び出しており、2つのテンプレートパラメーターを処理しています。

  1. shared_ptrテンプレートタイプTAあなたの場合);

    get()T*あなたが試したときにそう戻ります:

    delete pa.get();
    

    ... sの子~A()のみがアクセスできるアクセスを試みたAため、エラーが発生しました。

    次の行で:

     delete static_cast<B*>(pa.get());
    

    ...あなたはダウンキャストA*B*て削除B*を呼び出したので、~B()アクセスした相手を呼び出しました。(~B()常に要求~A()して~A()いると宣言されていますvirtual

  2. shared_ptrコンストラクター引数テンプレートタイプY(この場合)に変換可能Bである必要がある要件(この場合は 継承としてアップキャストできます)。Y*T*B*A*BA

    ~shared_ptr()呼び出しdeleteますY*B*あなたの場合、~B()アクセス~A()して呼び出すことができます)。これはpa、スコープ外になったときに発生します(shared_ptrこれは、元の質問であった基本クラスで保護されたデストラクタにアクセスする方法です)。

boost::shared_ptr内部的に単一のポインタを保持します。作成するときは、コンストラクターにSINGLEboost::shared_ptrポインターを渡します。これは、これら2つのテンプレート引数タイプのいずれかへのポインターと見なす/変換することができます。

于 2012-05-01T12:29:25.620 に答える
0

これは、ブーストテンプレートの定義により、共有ポインターがテンプレートのインスタンス化から<ClassT>クラスのフレンドであると宣言されているためだと思います。

これは、ブート共有ポインターヘッダーファイルからコピーしたスニペットです。

// Tasteless as this may seem, making all members public allows member templates
// to work in the absence of member template friends. (Matthew Langston)

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS

private:

    template<class Y> friend class shared_ptr;
    template<class Y> friend class weak_ptr;


#endif
于 2012-05-01T11:37:23.903 に答える