1

のようなキューの実装があり、template <typename T> queue<T>さまざまstruct QueueItem { T data;}な場所(このキューを介した1つのプロデューサースレッドからコンシューマースレッドへのデータの通過を含む)間でデータの通過を計測する別のライブラリがあります。これを行うために、そのタイミングライブラリのコードをキューのプッシュ関数とポップ関数に挿入し、それらが割り当てるときに、そのライブラリのタイミングメタデータにBufferItem.data追加したタイプの追加メンバーも割り当てます。void*つまり、以前は次のようなものでした。

void push(T t)
{
  QueueItem i;
  i.data = t;
  //insert i into queue
}

なりました

void push(T t)
{
  QueueItem i;
  i.data = t;

  void* fox = timinglib.getMetadata();
  i.timingInfo = fox;
  //insert i into queue
}

QueueItemが

struct QueueItem
{
 T data;
}

struct QueueItem
{
  T data;
  void* timingInfo;
}

しかし、私が達成したいのは、タイミングライブラリがアクティブ化されていないときはいつでも、後者の構造体からより軽量の構造体を優先して交換できることです。何かのようなもの:

if timingLib.isInactive()
 ;//use the smaller struct QueueItem
else
 ;//use the larger struct QueueItem

できるだけ安く。これを行うための良い方法は何でしょうか?

4

2 に答える 2

1

これはランタイムの選択である必要があり、タイミングを有効/無効にして 2 つの異なるバイナリをビルドすることはできないという私の仮定を確認することから始めます。このアプローチにより、どのアプローチでも可能な限り多くのオーバーヘッドが排除されます。

それでは、異なる実行時の動作が必要であると仮定しましょう。ランタイムの決定が必要になるため、いくつかのオプションがあります。ポリモーフィズムの(比較的小さい)コストを回避できる場合は、キューをポリモーフィックにし、起動時に適切なインスタンスを作成してから、pushたとえば、余分なデータを追加するかどうかを指定できます。

ただし、それがオプションでない場合は、テンプレートを使用して目的を達成できると思いますが、事前の作業が必要になる可能性があり、余分なコードでバイナリのサイズが大きくなる可能性があります。

クラスにタイミングを追加するためのテンプレートから始めます。

template <typename Timee>
struct Timed : public Timee
{
    void* timingInfo;
};

次に、時間指定された QueueItem は次のようになります。

Timed<QueueItem> timed_item;

タイミングを気にしないものにとっては、このクラスは とまったく同じように見えQueueItemます。必要に応じて、自動的に親にアップキャストまたはスライスします。また、メソッドがタイミング情報を知る必要がある場合は、何をすべきかを知るオーバーロードを作成するかTimed<T>、実行時チェック (「タイミングが有効です」フラグの場合) を行い、正しい型にダウンキャストします。

Queue次に、ベースQueueItemまたはTimedバージョンのどちらを使用しているかを知るために、インスタンス化を変更する必要があります。たとえば、考えられるメカニズムの非常に大まかなスケッチは次のとおりです。

template <typename Element>
void run()
{
    Queue<Element> queue;

    queue.setup();
    queue.process();
}

int main()
{
    if(do_timing)
    {
        run<Timed<QueueItem> >();
    }
    else
    {
        run<QueueItem>();
    }

    return 0;
}

メタデータの取得がステートレスである場合を除き、アイテムQueueで使用する場合は「可能性が高い」特殊化が必要です。この場合、コンストラクターは情報を収集し、作成時に自己入力できます。その後、同じままで、使用しているインスタンス化に依存します。TimedTimedQueue

于 2012-07-25T14:48:38.560 に答える
1

明らかに、同時に大きい構造体と小さい構造体を持つことはできないため、何らかの形式の継承、ポインター/参照、または共用体を検討する必要があります。

T に「予備の」データがあり、timingInfo が占める可能性がある場合は、ユニオンが理想的です。そうでない場合は、オリジナルと同じくらい「重い」ものになります。

継承を使用すると、そこにvtableが追加されてパディングが多すぎるため、元のサイズと同じくらい大きくなる可能性があります。

したがって、次のオプションは、ポインターのみを保存し、保存するデータ (データまたはデータ + タイミング) を指すようにすることです。この種のパターンは ' flyweight ' として知られています - 操作されるオブジェクトとは別に共通のデータが保存されます。これが探しているものかもしれません (タイミング情報のメタデータによって異なります)。

もう 1 つのより複雑な方法は、同期を保つ 2 つのキューを用意することです。一方にデータを保存し、もう一方には関連するタイミング情報を保存します (有効な場合)。有効にしない場合、2 番目のキューは無視されます。これに関する問題は、2 つの同期を維持することですが、これは技術的な問題ではなく、組織の問題です。おそらく、2 つの実際のキューを内部に含む新しい Queue クラスを作成します。

于 2012-07-10T16:24:28.343 に答える