好吧,分析器从不撒谎。
由于我有一个非常稳定的 18-20 类型的层次结构,变化不大,我想知道是否只使用一个简单的枚举成员就可以解决问题并避免 RTTI 所谓的“高”成本。如果 RTTI 实际上比if
它引入的声明更昂贵,我持怀疑态度。男孩哦,男孩,是吗。
事实证明,RTTI很昂贵,比C++ 中的等效if
语句或简单的原始变量要昂贵得多。switch
所以 S.Lott 的回答并不完全正确, RTTI需要额外的成本,这不仅仅是因为混合了一个if
声明。这是因为 RTTI 非常昂贵。
此测试是在 Apple LLVM 5.0 编译器上完成的,并启用了库存优化(默认发布模式设置)。
因此,我有以下 2 个函数,每个函数都通过 1) RTTI 或 2) 一个简单的开关来确定对象的具体类型。它这样做了 50,000,000 次。事不宜迟,我将向您展示 50,000,000 次运行的相对运行时间。
没错,它dynamicCasts
占用了94%的运行时间。而regularSwitch
块只占3.3%。
长话短说:如果你有能力enum
像我在下面做的那样连接一个 'd 类型,我可能会推荐它,如果你需要做 RTTI并且性能是最重要的。它只需要设置一次成员(确保通过所有构造函数获取它),并且确保以后永远不要编写它。
也就是说,这样做不应该弄乱你的 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 ) ;
}