まあ、プロファイラーは嘘をつかない。
私は18-20タイプの非常に安定した階層を持っているため、あまり変化しないので、単純なenum'dメンバーを使用するだけで問題が解決され、RTTIの「高」コストを回避できるのではないかと思いました。RTTIが実際にif
それが紹介する文よりも高価であるかどうか、私は懐疑的でした。ああ、そうですか。
RTTI は高価であり、同等のステートメントやC ++のプリミティブ変数の単純なステートメントよりもはるかに高価であることがわかります。したがって、S.Lottの答えは完全に正しいわけではありません。RTTIには追加のコストがかかります。それは、単に声明が混在しているためではありません。これは、RTTIが非常に高価であるためです。if
switch
if
このテストはApple LLVM 5.0コンパイラで行われ、ストックの最適化がオンになっています(デフォルトのリリースモード設定)。
したがって、私は以下の2つの関数を使用します。各関数は、1)RTTIまたは2)単純なスイッチを介してオブジェクトの具体的なタイプを計算します。それは50,000,000回そうします。さらに面倒なく、50,000,000回の実行の相対的な実行時間を示します。
そうです、実行時間の94%がdynamicCasts
かかりました。一方でブロックのみを取った3.3%regularSwitch
。
要するにenum
、以下のように 'd型をフックするエネルギーを確保できるのであれば、RTTIを実行する必要があり、パフォーマンスが最も重要な場合は、おそらくそれをお勧めします。メンバーの設定は1回のみです(必ずすべてのコンストラクターで取得してください)で確実に行われるようにします)、その後は絶対に記述しないでください。
そうは言っても、これを行ってもOOPプラクティスが台無しになることはありません。これは、タイプ情報が単に利用できず、RTTIを使い慣れている場合にのみ使用することを意図しています。
#include <stdio.h>
#include <vector>
using namespace std;
enum AnimalClassTypeTag
{
TypeAnimal=1,
TypeCat=1<<2,TypeBigCat=1<<3,TypeDog=1<<4
} ;
struct Animal
{
int typeTag ;// really AnimalClassTypeTag, but it will complain at the |= if
// at the |='s if not int
Animal() {
typeTag=TypeAnimal; // start just base Animal.
// subclass ctors will |= in other types
}
virtual ~Animal(){}//make it polymorphic too
} ;
struct Cat : public Animal
{
Cat(){
typeTag|=TypeCat; //bitwise OR in the type
}
} ;
struct BigCat : public Cat
{
BigCat(){
typeTag|=TypeBigCat;
}
} ;
struct Dog : public Animal
{
Dog(){
typeTag|=TypeDog;
}
} ;
typedef unsigned long long ULONGLONG;
void dynamicCasts(vector<Animal*> &zoo, ULONGLONG tests)
{
ULONGLONG animals=0,cats=0,bigcats=0,dogs=0;
for( ULONGLONG i = 0 ; i < tests ; i++ )
{
for( Animal* an : zoo )
{
if( dynamic_cast<Dog*>( an ) )
dogs++;
else if( dynamic_cast<BigCat*>( an ) )
bigcats++;
else if( dynamic_cast<Cat*>( an ) )
cats++;
else //if( dynamic_cast<Animal*>( an ) )
animals++;
}
}
printf( "%lld animals, %lld cats, %lld bigcats, %lld dogs\n", animals,cats,bigcats,dogs ) ;
}
//*NOTE: I changed from switch to if/else if chain
void regularSwitch(vector<Animal*> &zoo, ULONGLONG tests)
{
ULONGLONG animals=0,cats=0,bigcats=0,dogs=0;
for( ULONGLONG i = 0 ; i < tests ; i++ )
{
for( Animal* an : zoo )
{
if( an->typeTag & TypeDog )
dogs++;
else if( an->typeTag & TypeBigCat )
bigcats++;
else if( an->typeTag & TypeCat )
cats++;
else
animals++;
}
}
printf( "%lld animals, %lld cats, %lld bigcats, %lld dogs\n", animals,cats,bigcats,dogs ) ;
}
int main(int argc, const char * argv[])
{
vector<Animal*> zoo ;
zoo.push_back( new Animal ) ;
zoo.push_back( new Cat ) ;
zoo.push_back( new BigCat ) ;
zoo.push_back( new Dog ) ;
ULONGLONG tests=50000000;
dynamicCasts( zoo, tests ) ;
regularSwitch( zoo, tests ) ;
}