3

クラスの共有ポインターを作成する必要があります。他の多くのことの中で、共有ポインターが指しているオブジェクトを削除できるようにする必要があります。

保護されたデストラクタを持つオブジェクトで動作するソリューションをコーディングするにはどうすればよいですか?

deleteさらに、placement new を使用してオブジェクトが作成された場合、そのスペースがまだ使用されている可能性があるため、オブジェクトを呼び出すべきではありません(delete呼び出しは機能しますか?)。そのようなケースをどのように検出できますか?

仕様の関連ビット:

void reset(); スマート ポインターは、ヌル ポインターを指すように設定されます。現在ポイントされているオブジェクトの参照カウントがあれば、その参照カウントが減分されます。

Sptr(); null ポインターを指すスマート ポインターを構築します。

template <typename U> Sptr(U *); 指定されたオブジェクトを指すスマート ポインターを構築します。参照カウントは 1 に初期化されます。

Sptr(const Sptr &);
template <typename U> Sptr(const Sptr<U> &);

参照カウントがインクリメントされます。U * が暗黙的に T * に変換できない場合、構文エラーが発生します。適切な操作のためには、通常のコピー コンストラクターとメンバー テンプレート コピー コンストラクターの両方を指定する必要があることに注意してください。

コードの呼び出し方法:

        Sptr<Derived> sp(new Derived);
        char *buf = (char *) ::operator new(sizeof(Sptr<Base1>));
        Sptr<Base1> &sp2 = *(new (buf) Sptr<Base1>());
        sp2 = sp;
        sp2 = sp2;
        sp.reset();
        sp2.reset();
        ::operator delete(buf);

Base1すべてが保護されています。

4

4 に答える 4

4

デストラクタを非公開にすることの要点は、オブジェクトが勝手に破棄されるのを防ぐことです。それを回避する良い方法はありません。(一般的な方法があったとしても、そのためにはカプセル化を完全に破る必要があるため、良い方法ではありません。)

オブジェクトをそれ自体以外のクラスによって破棄したい場合は、デストラクタを public にします。そうしないと、ポインタークラスもオブジェクトを破棄できなくなります。

または、ポインター クラスを、操作したいクラスのフレンドにすることもできます。しかし、これは多くの点で醜いものです。特に、使用できるオブジェクトの有効なタイプがかなり恣意的に制限されます。

于 2012-11-26T19:59:12.400 に答える
2

参照カウンターとともに、オブジェクトを削除する関数へのポインター (「deleter」) を格納します。スマート ポインターのテンプレート化されたコンストラクターでデリータをインスタンス化すると、派生型がわかります。以下は非常に単純な疑似コードです。

template<class T> void DefaultDeleter(void *p) { delete static_cast<T*>(p); }

struct ref_counter {
    int refs;
    void *p;
    void (*d)(void *);
};

template<class T> class Sptr { 
    /* ... */
    template <typename U> Sptr(U *p)
    {
        _c = new ref_counter;
        _c->refs = 1;
        _c->p = static_cast<void*>(p);
        _c->d = &DefaultDeleter<U>;
        _p = p;
    }

    T *_p;
    ref_counter *_c;
};

refsゼロになったら、呼び出して、指定(*_c->d)(_c->p)されたオブジェクトを破棄します。

Baseもちろん、のデストラクタは保護されており、のデストラクタはパブリックであると想定していDerivedます。そうでなければ、演習は意味をなさないからです。

注:std::shared_ptrこれが、非仮想デストラクタを持つ基本クラスで安全に使用できる理由です。

于 2012-11-26T20:20:33.023 に答える
0

あなたのクラスは、オブジェクトの割り当て解除を担当するdeleter functorを取ることができます。これを行うことで、デストラクタへのアクセスの問題を、クラスを使用している人に投げかけることができます。:)

冗談はさておき、呼び出し元がクラスのインスタンスを作成する方法を知っている場合、それらのインスタンスを破棄する方法も知っている必要があります。

これは、配置に関連する問題を解決する方法も提供しますnew

于 2012-11-26T19:53:03.863 に答える
0

仕様の更新を読んだ後、次の理由により、それを適切に実装する方法はないと言えます。

  • ポインターが新しいケースと新しいケースを区別する方法はありません。デリータができる唯一のことは、 を呼び出すことですdelete p。これは配置の新しいケースでは正しいことではありませんnewが、バッファーがたまたま正しいサイズであり、 .
  • 他の回答で説明されているように、削除者が保護されたデストラクタの問題を回避する良い方法はありません。

コンストラクターにカスタムのデリータの可能性を追加することで、これらの問題の両方を解決できます。

編集:これは、カスタム デリーターを追加する方法です。

template <typename U> Sptr(U *, std::function<void(T*)> &&deleter); 指定されたオブジェクトを指すスマート ポインターを構築します。参照カウントは 1 に初期化されます。カスタム デリータは、参照カウントがインスタンスへの生ポインタでゼロに達すると呼び出されます。

于 2012-11-26T20:13:31.197 に答える