1

X:関連のないさまざまな種類のオブジェクトを処理する、関連のないコンテナーのようなオブジェクト (ベクター、マップ、ツリーなど) のコレクションがあります。これらのコンテナー内のオブジェクトの有効期間は、コンテナーの一部のサブセット間で共有されます。それらの同期を担当するオブジェクトがあります。私が考えることができる同期クラスの最も単純な実装は、私が管理したいすべてのコンテナーのようなオブジェクトに共通のインターフェイスを実装するクラスになるBaseContainerLikeポインターのベクトルを持つことです。BaseContainerLikeしかし、それらのすべてがコンテナのようなわけではありません。それらはコンテナのように使用できますが、共通の基本クラスから継承することは非常に奇妙に感じられ、私のデザインが非常に強く結合されるのではないかと心配しています.

だから私はContainerLikeInterfaceこのようなクラスを作成しました:

struct ContainerLikeInterface {
template<T>
ContainerLikeInterface(T& t) 
 : create([](int i){ return t->create(i); }),    // this is just an example
   delete([](int i){ return t->delete(i); }) {}

std::function<void(int)> create;
std::function<void(int)> delete;
};

template<class T>
ContainerLikeInterface make_containerLikeInterface(T& t) {
  return ContainerLikeInterface(t);
}

これにより、邪魔にならない方法でインターフェースのベクトルを自明に作成できます (コンストラクターをさまざまな型に部分的に特化することができます)。このアプローチを使用したコードは、継承を使用した場合よりもわずかに高速ですが、必要なメモリがわずかに多くなり、コンパイル時間が長くなります (ただし、コンパイル時間は優先しません)。ただし、このアプローチが私のプロジェクトにうまく適合するかどうかはわかりません。また、人々がオブジェクトの所有権をインターフェイスに移すことを好む値セマンティクスに関する記事をいくつか読んだので、次の質問があります。

  • このアプローチの長所/短所は何ですか?
  • これは長期的に私にいくつかの問題を与えるでしょうか?
  • 代わりに継承を使用する必要がありますか?
  • これを別の方法で実装する必要がありますか?
  • 代わりにライブラリを使用する必要がありますか? ( boost::TypeErasureadobe::poly、またはpyrtsa/poly )
4

3 に答える 3

1

このインターフェースは、 Rust object systemで作成されたインターフェース システムに少し似ています 。従来の VMT ベースのインターフェイスには、VMT へのポインターを保持するオブジェクトへのポインターがあります。あなたのものには2つのポインターがあります.1つはオブジェクトへ、もう1つはメソッドテーブルへです。[ほぼ]常に、あなたがすでに述べた欠点(メモリ使用量など)を持つ仮想関数よりも強力に見えます。速度に関してstd::functionは、標準のアロケータを使用してへのポインタを保持しますt。コンストラクターを頻繁に呼び出すと、インターフェイスContainerLikeInterfaceごとに少なくとも 1 つの割り当てが必要でstd::functionあり、独自に作成できるため、パフォーマンスが低下する可能性があります。

于 2013-03-07T21:15:59.380 に答える
1

あなたの基本的な考え方(継承を必要としない)は良いです。代わりに Adob​​e.Poly を使用することをお勧めします。1 回の操作で 1 つを使用するstd::functionと、N 個の仮想テーブル (ポインター) と、潜在的に N 個のヒープ割り当て (SBO (Small Buffer Optimization) を適用できるかどうかによって異なります) があります。

また、オブジェクトのライフタイム管理の問題に陥る可能性が非常に高くなります。実装では、実際のオブジェクトは「インターフェース」よりも長く存続すると想定しています。遅かれ早かれ、あなたはそれを間違えるでしょう。これが、価値セマンティックなアプローチを推奨する理由です。Adobe.Poly がそれを提供します。

Adobe.Poly を使用すると、1 つの vtable (ポインター) しか取得できません。また、SBO も実装しています。単一の割り当てではない可能性があります。

Boost.TypeErasure を使用する必要はありません。多くのメタプログラミングを利用するインターフェースを指定するための別の「言語」を学習する必要があり、現在のところ SBO は実装されていません。

Adobe.Poly は十分に文書化されていません。使用方法の例については、この投稿を参照してください。また、実装方法については、このペーパーを参照してください。

于 2014-12-03T15:08:40.603 に答える
0

ContainerLikeInterface基本的に、ポインターまたは some への参照を持つインターフェイスを持つプロキシ オブジェクトを作成していますT

派生できない標準コンテナを使用しながら、プロキシの作成を回避する方法がありますContainerLikeInterface。これはおそらくMix-in デザイン パターンと呼ばれ、C++11 での完全転送では次のようになります。

#include <vector>

struct IContainerLikeInterface
{
    virtual void create(int) = 0;
    virtual void erase(int) = 0;
};

template<class T>
struct ContainerLikeInterface : T, IContainerLikeInterface
{
    template<class... Args>
    ContainerLikeInterface(Args&& ...args) 
        : T(std::forward<Args>(args)...)
    {}

    // implement IContainerLikeInterface
    void create(int) override;
    void erase(int) override;
};

int main() {
    ContainerLikeInterface<std::vector<int> > v(10);
    v.size();
}

ただし、問題のコンテナーのすべての宣言 ( などstd::vector<int>) を に変更する必要があるため、煩わしくなりContainerLikeInterface<std::vector<int> >ます。ContainerLikeInterface<T>is-aであるため、使用方法は同じままTです。

于 2013-03-06T19:33:27.583 に答える