3

私は、さまざまなタイプ (プロパティ、親、子など) で構成されるモデルに反対しています。各タイプは、ac api の一連の関数に関連付けられています。例えば:

Type "Properties":
  char* getName(PropertiesHandle);
  char* getDescription(PropertiesHandle);

Type "Parent"
  PropertiesHandle getProperties(ParentHandle);
  ChildHanlde getFirstChild(ParentHandle);

Type "Child"
  PropertiesHandle getProperties(ChildHandle);
  ParentHanlde getParent(ChildHandle);
  ChildHandle getNextChild(ChildHandle);

次のように、この c api ライブラリの一連の C++ インターフェイスを作成しました。

class IProperties
{
public:
  virtual std::string getName() = 0;
  virtual std::string getDescription() = 0;
};

class IParent
{
public:
  virtual std::shared_ptr<IProperties> getProperties() = 0;
  virtual std::shared_ptr<IChild> getFirstChild() = 0;
};

class IChild
{
public:
  virtual std::shared_ptr<IProperties> getProperties() = 0;
  virtual std::shared_ptr<IParent> getParent() = 0;
  virtual std::shared_ptr<IChild> getNextChild() = 0;
};

次に、Properties、Parent、および Child クラスを介してこれらのインターフェイスを実装します。

したがって、Child インスタンスはコンストラクターを介して特定の ChildHandle を取得し、その getParent 関数は次のようになります。

std::shared_ptr<IParent> getParent()
{
    // get the parent handle and wrap it in a Parent object
    return std::shared_ptr<IParent>(new Parent(_c_api->getParent(_handle)));
}

あなたの意見では、ここで shared_ptr を返すことは合理的ですか。私は std::unique_ptr を使用できません。Google Mock では、モック化されたメソッドのパラメーターと戻り値をコピー可能にする必要があるためです。Google Mock を使用して、テストでこれらのインターフェイスをモックしています。

循環参照の可能性を提示する可能性がある将来、物事がどのように最適化されるかについても考えています。これは、キャッシングを使用して C API への複数回の呼び出しを回避する (たとえば、子がその親を複数回確立する必要がない) 場合に、親を取得する Child コンストラクターと組み合わせて使用​​する場合に発生する可能性があります。これには、インターフェイスと多くのコードを変更するweak_ptrsの使用が必要になります...

4

3 に答える 3

2

を返すことに問題shared_ptrはありませんが、これが最善の選択肢ではない可能性があることを納得させようとします。

スマート ポインターを使用すると、安全性の利点が得られますが、API のユーザーは、ニーズに最適なタイプのスマート ポインターを使用するという柔軟性を失い、代わりに常に を使用する必要がありますshared_ptr

また、柔軟性よりも安全性をどれだけ重視するかにもよりますが、個人的にはネイキッド ポインターを返して、ユーザーが必要なスマート ポインターを使用できるようにすることを検討します。もちろん、shared_ptr何らかの理由で使用する必要がある場合は使用します。

于 2012-08-06T12:39:52.693 に答える
2

重要な質問は、返されたポインターのセマンティクスは何ですか?

  • 返された親/子/プロパティ オブジェクトが、返された (おそらく、何らかの意味で所有している) オブジェクトとは独立しshared_ptrた有効期間を持つ場合、 を返すのが妥当です: これは、呼び出し元と呼び出し先がオブジェクトの有効期間を決定する同等の権利を持っていることを示します。

    std::shared_ptr<IChild> child = parent->getFirstChild();
    // now I can keep child around ... if parent is destroyed, one
    // orphaned subtree is magically kept around. Is this desirable?
    
  • 返されたオブジェクトの有効期間が呼び出し先自身の有効期間に依存する場合、次のようになります。

    • shared_ptr返されたオブジェクトの寿命を呼び出し先の寿命よりも長くすることは、呼び出し元にとって意味があると誤って示唆します
    • unique_ptr所有権の譲渡を誤って提案する
    • 生のポインターは、誤解を招く約束を明示的に行いませんが、正しい使用についてのヒントも与えません

したがって、呼び出し元が所有権の譲渡やオブジェクトの有効期間の延長なしに、オブジェクトの内部状態への作業参照を取得するだけの場合、スマート ポインターの使用は推奨されませ

参照を返すことを検討してください。

于 2012-08-06T13:03:39.170 に答える
0

shared_ptr問題はありませんが、C++11 のサポートなど、エンド ユーザーにいくつかの制限を提供します。生のポインター、またはスマート ポインターを調整できるようにするトレイトは、エンド ユーザーにより多くの柔軟性を提供する場合があります。

ポインターに関係なく、実装によって導入されたセマンティクスに注意することをお勧めします。現在の実装では、すべてのアクセサー呼び出しに対して新しいラップがインスタンス化されているため、同等性チェックは失敗します。次のコードを検討してください。

auto child = parent->getFirstChild();
if ( parent == child->getParent() ) // Will be false, as they point to different
                                    // instantiations of Parent.
  ...

if ( child->getParent() == child->getParent() ) // False for the same reason.
  ...

auto sibling = child->getNextChild();
if ( parent == sibling->getParent() ) // Also false for the same reason.
  ... 

また、 を使用する場合は、割り当てで発生するオーバーヘッドの一部を削減するためにstd::shared_ptrを使用することを検討する価値があります。std::make_shared

于 2012-08-06T13:09:10.413 に答える