8

OK、共有ポインターの使用を開始し、可能な限り共有ポインターを渡します。生ポインタへの変換はもうありません。この特定のケースを除いて、これはうまく機能します。

次のように、別のクラスのオブザーバーでもあるクラスがあるとします。

class MyClass : public IObserver
   {
   public:
      MyClass (std::shared_ptr<SomeOtherClass> otherClass);
      void DoSomethingImportant();
   private:
      std::shared_ptr<SomeOtherClass> m_otherClass;
   };

このクラスは、私のアプリケーションでは次のように使用されます。

std::shared_ptr<MyClass> myInstance(new MyClass(otherInstance));
...
myInstance->DoSomethingImportant();

MyClass は、別のクラスへの共有ポインターを取得し、これを m_otherClass データ メンバーに格納します。DoSomethingImportant メソッドでは、MyClass インスタンスは、次のように m_otherClass のオブザーバーとして自身を登録するなど、多くの重要なことを行います。

m_otherClass->registerObserver(this);

問題は、registerObserver メソッドが次のように定義されていることです。

void registerObserver (std::shared_ptr オブザーバー);

共有ポインターが必要ですが、「this」は生のポインターであり、共有ポインターではありません。

これを解決するには、次の 3 つの方法があります。

  • 通常のポインターを共有ポインターに変換するトリックを見つけます (質問convert pointer to shared_ptr を参照)。しかし、その質問への回答は共有ポインターをコピーすることのみを示唆しており、ポインターを共有ポインターに実際に変換する方法については示唆していません。
  • 「myInstance->DoSomethingImportant(myInstance);」のように、自分自身への共有ポインタをメソッドに渡します。これは少しばかげているようです。
  • オブザーバー部分を別のクラスに入れます。これはやり過ぎのように見え、クラスを理解しにくくする可能性があります。

この問題は、共有ポインタが C++ への単なるアドオンであることを明らかにしています (C# (または一般的に .Net) や Java などの他の言語/環境では同じ問題があるとは思いません)。

この状況を処理する方法に関する他の提案やトリックはありますか?

4

4 に答える 4

8

あなたが必要とするのは、おそらくenable_shared_from_thisshared_from_this施設です。ドキュメントはこちら

shared_from_thisコンストラクターが完全に完了し、オブジェクトが別の によって所有されるまで使用できないことに注意してくださいshared_ptr

struct test : boost::enabled_shared_from_this<test>
{
    test() {
       // shared_from_this(this); // error, still not owned by another shared_ptr
    }
    boost::shared_ptr<test> shared() {
       return shared_from_this(this);
    }
};
int main() {
   test * t = new test;
   // boost::shared_ptr<test> p = t->shared(); // error, not yet owned by other shared_ptr
   boost::shared_ptr<test> owner( t ); 
   boost::shared_ptr<test> p = t->shared();     // [*] ok, "owner" owns the object
}

[*] 例のこの部分はばかげています。メソッドを呼び出す代わりに、所有者を p にコピーできます。shared_from_thisメソッド内で呼び出すことができるかどうかに注意するために提示されていtestます。

于 2011-02-02T08:55:58.263 に答える
4

オブザーバーパターンの場合、オブザーバーオブジェクトはオブザーバーの所有権を取得しません。生のポインターを使用しないのはなぜですか?オブザーバーのライフサイクルは、オブザーバー自身が制御する必要があります。

enable_shared_from_thisを使用して、オブザーバーとその監視対象オブジェクトにサイクル依存関係を導入します。つまり、明示的に削除しないと、リソースが解放されることはありません。

于 2011-02-02T10:15:49.423 に答える
0


登録ステップを別の方法に移動できますか? :

shared_ptr<SomeOtherClass> other(new SomeOtherClass());
shared_ptr<MyClass> my(new MyClass());
// register myself to the observer  
other->registerObserver(my);
my->DoSomethingImportant();

オブザーバー パターンの適切な設計は、boost::signal および boost::bind ライブラリを使用して実装できます。ぜひご覧ください。

よろしく、
マルシン

于 2011-02-02T09:07:24.447 に答える
0

コンストラクターをプライベートにして、次のような静的な構築メソッドを使用するのはどうですか:

class MyClass : public IObserver
   {
   public:
      static std::shared_ptr<MyClass> createObserver(std::shared_ptr<SomeOtherClass> otherClass);
      void DoSomethingImportant();
   private:
      MyClass (std::shared_ptr<SomeOtherClass> otherClass);
      std::shared_ptr<SomeOtherClass> m_otherClass;
   };

次に、静的メソッドでオブザーバーをきれいにインスタンス化でき、 this ポインターについてまったく心配する必要がなくなります。

于 2011-02-02T08:37:25.777 に答える