ライブラリインターフェイスでweak_ptrへのアクセスを提供するのは賢明ですか?

StackOverflow https://stackoverflow.com/questions/631380

  •  08-07-2019
  •  | 
  •  

質問

関連する複数のオブジェクトタイプへの参照を公開するライブラリを作成しました。これらのオブジェクトはすべて、boost::shared_ptr

を介して内部的にライブラリによって管理される有効期間を持っています

ライブラリのユーザーは、ライブラリの性質により、公開されたオブジェクトの寿命を知ることもできます。そのため、ポインタを保存したり、これらのオブジェクトへの参照を保持したりできます。彼らがこれを行い、それらのオブジェクトがいつ有効でなくなるかを知ることは合理的です。

しかし、私はユーザーに合理的であることを強いる罪を感じます。

ライブラリがオブジェクトにweak_ptrを公開することは許容されますか?他のライブラリでこれを行っていますか?

このライブラリのアプリでの使用状況をプロファイルしましたが、<=>を独占的に公開するにはミッションクリティカルであることがわかりました。

一致するAPI関数に参照または weak_ptrを公開させるか、オブジェクトを<=>自体に公開できるようにするのが賢明でしょうか?

役に立ちましたか?

解決

ライブラリのユーザーがsmart_ptrに既に直接アクセスできる場合、対応するweak_ptrのコンストラクターを介して、単にshared_ptrにアクセスできます。しかし、<=>がすべてライブラリの内部にある場合、それは別の話です。

その場合、ライブラリが提供する他のアクセスに加えて、各オブジェクトに<=>を自分自身に渡すことをお勧めします。これにより、ユーザーに最大の柔軟性が提供されます。<=>が必要な場合、すぐにアクセスできます。 <=>が必要な場合、簡単に取得できます。オブジェクト自体へのアクセスのみが必要な場合は、スマートポインターを完全に無視できます。

もちろん、あなたのライブラリが何をするのか、それがどのように使用または設計されているのかはわかりません。それが私の推奨事項を変えるかもしれません。

他のヒント

ライブラリのオブジェクトを取得するための複雑なメカニズムを考え出すと、ライブラリを使用していない人しかいません。ライブラリのセマンティクスにより、weak_ptrsを使用する必要がある場合は、オブジェクトがいつかなくなる可能性があることをユーザーが回避する方法はありません。インターフェースでライブラリの使用に関する情報をできるだけ多く表現し、ドキュメントを控え、無限に使いやすくします。

悪い/経験の浅いユーザーを中心に設計することはできません。

クライアントにweak_ptrへのアクセスを許可すると、クライアントをロックしてshared_ptrを作成し、オブジェクトの破棄を遅らせることができます。ライブラリーに問題が生じる可能性があります。

他のクラスでweak_ptr<T>::lock()をラップし、呼び出し元にshared_ptr<InterfaceClass>を与えることをお勧めします。そうすれば、彼らは単に<=>を呼び出すことはできません。あなたはそれを実装する方法に影響を与えるかもしれないパフォーマンスの制約を持っているように見えますが、<=>は良い方法であり、あなたのライブラリの内部にある<=>でクラスを維持するかもしれません。

これらの実装の詳細をライブラリインターフェースから除外し、インターフェースを変更せずに実装方法を変更できます。

特に TR1には同様のスマートポインターがあります(PDF)。

TR1は、主にVisual StudioとGCCによって実装されていますが、他のコンパイラの一部は実装されていません。ただし、気になるすべてのコンパイラで実装されている場合は、代わりにこれらのスマートポインターを公開するようにAPIを作り直す必要があります。

ライブラリの無効な使用(オブジェクトが削除されたときにアクセスしようとする)と高性能API(APIにweak_ptrおよびshared_ptrがない)の両方をトラップしたい場合は、デバッグビルドと非デバッグビルド用の異なるAPI。

簡単にするために、公開するオブジェクトのクラスは1つだけであるとします。このクラスオブジェクトを呼び出します。内部オブジェクトにアクセスするためにAPIから返すポインタータイプは、次のように定義されます。

#ifdef DEBUG
typedef ObjectPtrFacade ObjectPtr 
#else
typedef Object * ObjectPtr;
#endif

ここで、ファサードはあなたが書くクラスです。おおよそ次のように機能します:

class ObjectPtrFacade {
public:
    ObjectPtrFacade(Object *o) : wptr(o) { }
    // copy constructor and assignment here etc. (not written)
    Object * operator -> () const { return access(); }
    Object & operator * () const { return *access(); }
private:
    Object * access() { 
      assert(wptr.use_count() > 0);
      return (Object *)(wptr.lock());
    }
    weak_ptr<Object> wptr; 
}

この方法では、デバッグビルドをビルドするたびに、use_count()がゼロよりも大きい、つまりオブジェクトがまだ存在していることをオブジェクトにアクセスする前にアサートする、使用中の特別な種類のスマートポインターがあります。オブジェクトが解放された場合、失敗したアサートを取得します。これは、nullポインター参照よりも優れています。

もちろん、<!> quot; stupid <!> quot;がある場合、weak_ptrを使用しても役に立ちません。 APIユーザー

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top