5

だから私はクラスsomeBase{}を持つライブラリを作成しています。これは、多くのクラスのダウンストリームユーザーによって導出されます。

class someBase {
  public:
    virtual void foo()=0;
};

私も持っているのは、someBaseへのポインターのベクトルであり、これを実行しています:-

vector <someBase*> children;

// downstream user code populates children with some objects over here

for (i=0; i<children.size(); i++)
  children[i]->foo();

現在、プロファイリングは、仮想呼び出しでのブランチの予測ミスが、私のコードの(いくつかの)ボトルネックの1つであることを示唆しています。私が探しているのは、どういうわけかオブジェクトのRTTIにアクセスし、それを使用してクラスタイプに従って子のベクトルを並べ替え、命令キャッシュの局所性と分岐予測の両方を改善することです。

これを行う方法に関する提案/解決策はありますか?

覚えておくべき主な課題は次のとおりです:-

1.)someBaseから派生するクラスがどれか、またはいくつになるかはわかりません。仮に、ダウンストリームユーザーが編集して独自のクラスタイプを追加し、それを並べ替えることができる共通ファイルのどこかにグローバル列挙型を含めることができます(基本的には独自のRTTIを実装します)。しかし、それは醜い解決策です。

2.)PiotrNyczは、以下の回答でtype_infoを使用することを提案しています。ただし、そのために定義されているのは!=と==のみです。type_infoで厳密な弱順序を導出する方法に関するアイデアはありますか?

3.)分岐予測と命令キャッシュの局所性を改善することを本当に望んでいるので、別の解決策があれば、それも歓迎されます。

4

2 に答える 2

4

オペレーターがいtypeidます。

これを使用して、オブジェクトをベクトルでソートするためのコンパレータを定義できます。

このような:

inline bool compareTypes(BaseClass* obj1, BaseClass* obj2)
{
   int compareRes = strcmp(typeid(*obj1).name(), typeid(*obj2).name());
   if (compareRes < 0) return true;
   if (compareRes > 0) return false;
   std::less<BaseClass*> ptrComp;
   return ptrComp(obj1, obj2); 
}

と:

  sort(v.begin(), v.end(), compareTypes);

[アップデート]

この目的のために設計された関数があることを私に知らせてくれてありがとう。つまりstd::type_info::before(const type_info&) const、コンパレータは次のように簡単になります。

inline bool compareTypes(A* obj1, A* obj2)
{
   return typeid(*obj1).before(typeid(*obj2));
}

私の以前のバージョンはそれほど悪くはありません;)特定のクラスのオブジェクトもソートする必要がある場合に使用できます。

于 2012-09-19T20:12:43.403 に答える
0

たとえば、次のように使用して、初期化で1回タイプ別にポインタを分類できます。

std::vector<derivedA*> derivedA_list;
std::vector<derivedB*> derivedB_list;
//...

for (i=0; i<children.size(); i++)
    if (derivedA *d = dynamic_cast<derivedA*>(children[i]))
        derivedA_list.push_back(d);
    else if (derivedB *d = dynamic_cast<derivedB*>(children[i]))
        derivedB_list.push_back(d);
    //...

次に、関数を呼び出すために、非仮想呼び出しを行うことができます。

for (i=0; i<derivedA.size(); ++i)
    derivedA_list[i]->derivedA::foo();
for (i=0; i<derivedB.size(); ++i)
    derivedB_list[i]->derivedB::foo();

また、イテレータを使用するループは、より適切に最適化される可能性が高いことに注意してください。

于 2012-09-19T20:18:09.087 に答える