13

現在、ブーストenable_shared_from_thisと多重継承を使用するときにいくつかの問題が発生しています。

このシナリオは次のように説明できます。

  1. クラスAはいくつかの機能を実装し、から継承する必要がありますenable_shared_from_this

  2. クラスBは別の機能を実装しており、から継承する必要がありますenable_shared_from_this

  3. クラスはand ( )Dから機能を継承しますABclass D : public A, public B {}

  4. クラスから一部のクラスB機能を使用するDと、例外が発生しました ( bad_weak_ptr)

  5. enable_shared_from_thisクラスから継承することDは私にとって選択肢ではありません

これを解決する方法がわかりません。

ああ、私は Visual C++ 2010 を使用しています。

4

3 に答える 3

8

A と B を enable_shared_from_this とは少し異なるものを使用するように変更できる場合は、Potatoswatter のソリューションを拡張します。コードは標準ライブラリ バージョンを使用しますが、boost の実装は類似している必要があります。以下の説明

#include <memory>
template<typename T>
struct enable_shared_from_this_virtual;

class enable_shared_from_this_virtual_base : public std::enable_shared_from_this<enable_shared_from_this_virtual_base>
{
    typedef std::enable_shared_from_this<enable_shared_from_this_virtual_base> base_type;
    template<typename T>
    friend struct enable_shared_from_this_virtual;

    std::shared_ptr<enable_shared_from_this_virtual_base> shared_from_this()
    {
        return base_type::shared_from_this();
    }
    std::shared_ptr<enable_shared_from_this_virtual_base const> shared_from_this() const
    {
       return base_type::shared_from_this();
    }
};

template<typename T>
struct enable_shared_from_this_virtual: virtual enable_shared_from_this_virtual_base
{
    typedef enable_shared_from_this_virtual_base base_type;

public:
    std::shared_ptr<T> shared_from_this()
    {
       std::shared_ptr<T> result(base_type::shared_from_this(), static_cast<T*>(this));
       return result;
    }

    std::shared_ptr<T const> shared_from_this() const
    {
        std::shared_ptr<T const> result(base_type::shared_from_this(), static_cast<T const*>(this));
        return result;
    }
};

したがって、意図は、struct Aが からパブリックに継承し、 からenable_shared_from_this_virtual<A>パブリックstruct Bに継承することenable_shared_from_this_virtual<B>です。どちらも同じ共通の仮想オブジェクトを共有しているためstd::enable_shared_from_this、階層には 1 つしかありません。

いずれかの classes を呼び出すと、から T* へshared_from_thisのキャストが実行されenable_shared_from_this_virtual<T>*、shared_ptr のエイリアシング コンストラクターが使用されるため、新しい shared_ptr は T* を指し、単一の共有ポインターと所有権を共有します。

上部のフレンドの使用は、誰もが仮想ベースの shared_from_this() メンバーに直接アクセスできないようにすることです。によって提供されるものを通過する必要がありますenable_shared_from_this_virtual<T>

例:

#include <iostream>

struct A : public enable_shared_from_this_virtual<A>
{
    void foo()
    {
        shared_from_this()->baz();
    }

    void baz()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct B : public enable_shared_from_this_virtual<B>
{
    void bar()
    {
        shared_from_this()->baz();
    }

    void baz()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct D: A, B {};


int main()
{
 std::shared_ptr<D> d(new D);
 d->foo();
 d->bar();
 return 0;
}
于 2013-02-18T17:25:16.190 に答える
4

Ashared_ptrは、目に見えないコンテナ オブジェクト、つまり「制御ブロック」に対するオブザーバです。このコンテナーは常にヒープ上にあり、スタック上にはありません。直接ハンドルを取得することはできません。shared_ptrおよびがweak_ptr唯一の観察手段を提供しますが、オブジェクトを所有する非表示レイヤーがまだ存在します。移入するのはその隠れ層enable_shared_from_thisです。

enable_shared_from_thisすべてのenable_shared_from_thisベースを個別に初期化する必要があるため、からの多重継承は許可されませんが、制御ブロックには特定のタイプのすべてのベース サブオブジェクトのリストを取得する方法がありません。取得できるのは、あいまいな基本エラーだけです。

私が見る唯一の解決策は、から継承するandのvirtual基本クラスを追加することです。この目的のために、特定のクラスを指定できます。ABenable_shared_from_this

struct shared_from_this_virtual_base
    : std::enable_shared_from_this< shared_from_this_virtual_base >
    {};

struct shared_from_this_base : virtual shared_from_this_virtual_base {};

struct A : shared_from_this_base { … };
struct B : shared_from_this_base { … };

しかし、別の問題があります:virtualベースからダウンキャストすることはできAません。またはを復元するには、これらのポインタを 内のある種のレジストリ構造に追加する必要があります。これはおそらく、別の CRTP パターンを に追加することで設定されます。C++ では通常よりもフットワークが少し多くなりますが、概念的な近道は見当たりません。Bshared_from_this_virtual_baseA*B*shared_from_this_virtual_baseshared_from_this_base

編集:ああ、ダウンキャストを取得する最も簡単な方法は、void*メンバーを入れてから、クライアントコードが知っているものにshared_from_this_virtual_baseキャストすることです。完全にエレガントではないにしても、かなり実用的です。または、より安全な代替手段を提供できます。D*Dboost::any

于 2013-02-18T16:00:50.070 に答える
2

標準は、どのように実装されるべきかについて少し曖昧shared_from_thisですが、Boost がリファレンス実装を提供しているため、すべての実装が一致しているようです。

コンストラクターを作成するboost::shared_ptr<D> myD(new D())と、からへshared_ptrの明確な変換があるかどうかが確認されます(これは、 type の基本クラスがあることを意味します)。変換が機能する場合、基本クラスの a は、新しく作成された を参照するように設定されます。D*enable_shared_from_this<X>*XDenable_shared_from_this<X>weak_ptr<X>shared_ptr

enable_shared_from_this<A>あなたのコードには、 toとの2 つの可能な変換がありますがenable_shared_from_this<B>、これはあいまいweak_ptrですmyD。つまり、メンバー関数がB後で呼び出さshared_from_this()れた場合、メンバーが設定されていないため、bad_weak_ptr例外が発生しenable_shared_from_this<B>ます。

于 2013-02-18T15:30:26.057 に答える