5

実行時のポリモーフィズムが必要だったので、を使用しdynamic_castました。
しかし今、私は2つの問題を抱えていました-dynamic_cast非常に遅かったです!(下にスクロールしてベンチマークを表示します。)

簡単に言えば、私はこの方法で問題を解決することになりましたstatic_cast

struct Base
{
    virtual ~Base() { }
    virtual int type_id() const = 0;

    template<class T>
    T *as()
    { return this->type_id() == T::ID ? static_cast<T *>(this) : 0; }

    template<class T>
    T const *as() const
    { return this->type_id() == T::ID ? static_cast<T const *>(this) : 0; }
};

struct Derived : public Base
{
    enum { ID = __COUNTER__ };  // warning: can cause ABI incompatibility
    int type_id() const { return ID; }
};

int main()
{
    Base const &value = Derived();
    Derived const *p = value.as<Derived>();  // "static" dynamic_cast
}

しかし、私は確かにこの問題に遭遇した最初の人ではないので、私はそれが尋ねる価値があるかもしれないと思いました:

このような自家製のソリューションを考え出す代わりに、将来この問題を解決するために使用できる有名なパターン/ライブラリはありますか?


サンプルベンチマーク

私が話していることを理解するために、以下のコードを試してください-私のマシンでの単なる呼び出しよりもdynamic_cast約 15倍virtual遅くなりました(以下のコードでは1620ミリ秒に対して110ミリ秒):

#include <cstdio>
#include <ctime>

struct Base { virtual unsigned vcalc(unsigned i) const { return i * i + 1; } };
struct Derived1 : public Base 
{ unsigned vcalc(unsigned i) const { return i * i + 2; } };
struct Derived2 : public Derived1
{ unsigned vcalc(unsigned i) const { return i * i + 3; } };

int main()
{
    Base const &foo = Derived2();
    size_t const COUNT = 50000000;
    {
        clock_t start = clock();
        unsigned n = 0;
        for (size_t i = 0; i < COUNT; i++)
            n = foo.vcalc(n);
        printf("virtual call: %d ms (result: %u)\n",
            (int)((clock() - start) * 1000 / CLOCKS_PER_SEC), n);
        fflush(stdout);
    }
    {
        clock_t start = clock();
        unsigned n = 0;
        for (size_t i = 0; i < COUNT; i++)
            n = dynamic_cast<Derived1 const &>(foo).vcalc(n);
        printf("virtual call after dynamic_cast: %d ms (result: %u)\n",
            (int)((clock() - start) * 1000 / CLOCKS_PER_SEC), n);
        fflush(stdout);
    }
    return 0;
}

単語virtualを削除してに変更dynamic_castするとstatic_cast、実行時間は79ミリ秒になります。したがって、仮想呼び出しは静的呼び出しよりも最大25%遅くなります。

4

2 に答える 2

3

のほとんどの用途は、ダブルディスパッチ(別名、ビジターパターンdynamic_castに置き換えることができます。これは2つの仮想呼び出しになりますが、ベンチマークでは、それでも7.5倍高速です。dynamic_cast

于 2012-09-10T01:48:36.173 に答える
2

この一定時間の実装に興味があるかもしれません:http://www.stroustrup.com/isorc2008.pdf

また、多くのアップキャストは特定の制約の下で単純化される可能性があることに注意してください。たとえば、多重継承を使用しない場合、浅い継承のみを使用する場合、またはタイプに共通の祖先がないことを保証する場合、一部の評価は短絡され、網羅的になる可能性があります評価(によって提供されるdynamic_cast)を実行する必要はありません。

いつものように、特定のユースケースと実際のクラス階層について、ベンダーの実装に対して実装をプロファイリングします。

于 2012-09-10T01:39:05.370 に答える