我知道dynamic_cast有运行时检查,因此考虑更安全(可以在失败时返回空指针)但比static_cast慢。但两者之间的开销有多糟糕?
我是否应该考虑在循环中使用static_cast来解决常规大型项目中的性能问题?或者差异很小,只与特殊的实时程序有关。
答案 0 :(得分:11)
你有资料吗?
规则是:
static_cast
。dynamic_cast
,并且您需要程序为您查找对象的运行时类型。就这么简单。所有其他考虑都是次要的。
答案 1 :(得分:5)
取决于动态演员如何进行类安全/正确性检查。在我所描述的系统中,它可以很快变成非常大量的字符串比较。这是一个足够大的交易,我们几乎使用assert_cast样式系统,其中静态强制转换是为了性能而动态用于调试。
答案 2 :(得分:2)
Tomalak Geret'kal是对的,当你知道时static_cast
,当你不知道时dynamic_cast
。如果您想避免成本,您必须以您知道的方式构建您的设计。在单独的容器中存储单独的类型将使您的循环逻辑更复杂,但您可以使用模板算法来修复它。
对于简单的继承树,它非常快。如果你在具有虚拟继承的复杂层次结构中横向抛射,那么它必须进行一次重要的搜索。
示例:
struct Base {virtual ~Base () {}};
struct Foo : Base {};
struct Bar1 : virtual Base {};
struct Bar2 : virtual Base {};
struct Baz : Bar1, Bar2 {};
Base * a = new Foo ();
Bar1 * b = new Baz ();
dynamic_cast <Foo *> (a); // fast
dynamic_cast <Bar2 *> (b); // slow
性能在很大程度上取决于编译器。测量,测量,测量!请记住,运行时类型信息通常被排除在外并且将位于非本地内存中 - 您应该考虑缓存在循环中要执行的操作。
答案 3 :(得分:0)
非常大的C ++代码库(例如Mozilla,OpenOffice)习惯于禁用 RTTI(因此无法使用dynamic_cast
和异常),因为仅仅包含的开销可执行文件中的RTTI数据被认为是不可接受的。特别是,据报道,由于额外的动态重定位,导致启动时间增加(我记得大约10%的数字)。
从未讨论过避免dynamic_cast
和异常所需的额外代码实际上是否更慢。
答案 4 :(得分:0)
我刚尝试了一个小型的演员基准(在我3岁的上网本上,所以数字很高,但很好)。这是测试设置:
class A {
public:
virtual ~A() {}
};
class B : public A {
};
#define IT(DO) \
for (unsigned i(1<<30); i; i--) { \
B* volatile b(DO); \
(void)b; \
}
#define CastTest(CAST) IT(CAST<B*>(a))
#define NullTest() IT(NULL)
int main(int argc, char** argv) {
if (argc < 2) {
return 1;
}
A* a(new B());
switch (argv[1][0]) {
case 'd':
CastTest(dynamic_cast)
break;
case 's':
CastTest(static_cast)
break;
default:
NullTest()
break;
}
return 0;
}
我发现高度依赖于编译器优化,所以这是我的结果:
(参见下面的评估)
00:
g++ -O0 -Wall castbench.cpp; time ./a.out _; time ./a.out s; time ./a.out d
real 0m7.139s
user 0m6.112s
sys 0m0.044s
real 0m8.177s
user 0m6.980s
sys 0m0.024s
real 1m38.107s
user 1m23.929s
sys 0m0.188s
O1:
g++ -O1 -Wall castbench.cpp; time ./a.out _; time ./a.out s; time ./a.out d
real 0m4.412s
user 0m3.868s
sys 0m0.032s
real 0m4.653s
user 0m4.048s
sys 0m0.000s
real 1m33.508s
user 1m21.209s
sys 0m0.236s
O2:
g++ -O2 -Wall castbench.cpp; time ./a.out _; time ./a.out s; time ./a.out d
real 0m4.526s
user 0m3.960s
sys 0m0.044s
real 0m4.862s
user 0m4.120s
sys 0m0.004s
real 0m2.835s
user 0m2.548s
sys 0m0.008s
O3:
g++ -O3 -Wall castbench.cpp; time ./a.out _; time ./a.out s; time ./a.out d
real 0m4.896s
user 0m4.308s
sys 0m0.004s
real 0m5.032s
user 0m4.284s
sys 0m0.008s
real 0m4.828s
user 0m4.160s
sys 0m0.008s
对于一个演员(在上面的测试中,我们总共有2**30
演员阵容),我们在上面的最小例子中得到以下时间:
-O0 71.66 ns
-O1 71.86 ns
-O2 -1.46 ns
-O3 -0.11 ns
负值可能是由于程序执行时的不同负载造成的,并且小到足以被丢弃为无意义(即== 0)。由于这里没有开销,我们必须假设编译器足够聪明以优化抛弃,即使我们说b
是易变的。因此,唯一可靠的值是70 ns的结果。