2011-08-04 5 views
2

これは、私がパフォーマンスについてあまり心配していないので、多少仮説的です。実際にどのオプションが実際には最も速く/最も効率的かを疑問に思っています。速いもの:仮想ベースまたはクロスキャストからのダウンキャスト?

は、私が過負荷をサポートしている訪問者のテンプレートの次のコードがあるとします。

#define IMPLEMENT_VISITOR_WITH_SUPERCLASS(superclass) \ 
    typedef superclass visitor_super_t;  \ 
    virtual void visit(Visitor& v) { v.visit(*this); } 
//----------------------------------------------------------------------------- 
// Implementation detail: 
// Selective dispatcher for the visitor - required to handle overloading. 
// 
template <typename T> 
struct VisitorDispatch { 
    static void dispatch(Visitor* v, T* t) { v->visit(*t); } 
}; 
// Specalization for cases where dispatch is not defined 
template <> struct VisitorDispatch<void> { 
    static void dispatch(Visitor* v, void* t) { throw std::bad_cast(""); } 
}; 

//----------------------------------------------------------------------------- 
// Derive visitors from this and 'Visitor'. 
template <typename T> 
class VTarget 
{ 
public: 
    // Don't really need a virtual dtor. 
    virtual void dispatch(T& t) = 0; 
}; 

//----------------------------------------------------------------------------- 
class Visitor 
{ 
public: 
    virtual ~Visitor() = 0; 

    template <typename T> 
    void visit(T& t) { 
     typedef VTarget<T> target_t; 
     target_t* tgt = dynamic_cast<target_t*>(this); 
     if (tgt) { 
      tgt->dispatch(t); 
     } 
     else { 
      // Navigate up inhertiance hierarchy. 
      // requires 'super' to be defined in all classes in hierarchy 
      // applicable to this visitor. 
      typedef typename T::visitor_super_t super; 
      super* s = static_cast<super*>(&t); 
      VisitorDispatch<super>::dispatch(this, s); 
     } 
    } 
}; 

//----------------------------------------------------------------------------- 
inline Visitor::~Visitor() {} 

これは、その後、一般的な訪問者を作成するために使用されます。

class CommonBase { 
    IMPLEMENT_VISITOR_WITH_SUPERCLASS(void) 
    virtual ~CommonBase() = 0; 
}; 
class A : public CommonBase { 
    IMPLEMENT_VISITOR_WITH_SUPERCLASS(CommonBase) 
}; 
class B : public CommonBase { 
    IMPLEMENT_VISITOR_WITH_SUPERCLASS(CommonBase) 
}; 

class MyVisitor 
    : public Visitor 
    , public VTarget<CommonBase> 
    , public VTarget<A> 
    , public VTarget<B> 
{ 
public: 
    virtual void dispatch(CommonBase& obj); 
    virtual void dispatch(A& obj); 
    virtual void dispatch(B& obj); 
}; 

訪問者を使用して、最終的dynamic_cast<>年代になりVisitorからVTarget<T>まではクロスキャストです。

の仮想ベースをVTarget<T>-MyVisitorにすることは、Visitorから直接継承する必要はありません。 Visitor :: visitコードのdynamic_cast<>は、仮想ベースからのダウンキャストの結果となります。Visitor

キャストを実行するとき、1つの方法が他の方法より高速ですか?それとも、仮想ベースを持っているためにサイズのペナルティを受けるだけですか?

+3

"キャストを実行するとき、一方の方法が他の方法より速くなっていますか?"これに答える唯一の賢明な方法は、実際に測定することです。そのことを幸運に思うのは、コードが間違っているからです。投票を終了する。 –

+2

また、訪問者の全体のポイントは、キャストする必要がないということです。 –

+0

@Alexandreこの訪問者がこのように実装される理由は、クラス階層の訪問者ターゲットに依存しないことです。こうすることで、クラス階層の一部がライブラリ内に存在し、クライアントコード内の別の部分が常駐することができます。 – Pete

答えて

1

クロスキャストの方法が仮想ベースの方法より速いようです。

スーパークラスへのフォールバック1回、100000000回の繰り返し、クロスキャスト方式で30.2747秒、仮想ベース方式で41.3999 - 約37%遅くなりました。

スーパークラスのオーバーロードに対するフォールバックなしで、クロスキャストは10.733秒で、仮想ベースは19.9982(86%遅く)です。

私は、どちらのモードでもdynamic_castがどのように動作するかを知りたいと思っていました。

+0

共有ライブラリ(.dllまたは.so)の訪問者コードとメインプログラムのクライアントコードで同じコードを試しましたか?私の賭けは、それが物事を大きく変えるということです。また、階層内のクラスの数を増やして、その拡張方法を確認してください。訪問可能クラスごとにビジタークラスに余分なポインターがあることに注意してください。 –

+0

これは単純なコンソールアプリケーションではありませんでした。私は、それが非常に堅牢ではないので、共有ライブラリのためのdynamic_castの使用を避けるのが一般的です。私はそれがかなり遅くなることを期待しています。推測すると、2つの方法のパフォーマンスの差はおそらくそれほど小さくありません。 – Pete

関連する問題