概述
“在正确的场合使用恰当的特性”
C++引入的额外开销体现在以下两方面:
编译时开销
模板、类层次结构、强类型检查等新特性,以及大量使用了这些新特性的C++模板、算法库都明显地增加了C++编译器的负担。但是应当看到,这些新机能在不增加程序执行效率的前提下,明显降低了广大C++程序员的工作量。
用几秒钟的CPU时间换取程序员几小时的辛勤劳动,附带节省了日后debug和维护代码的时间,这点开销当算超值。
当然,在使用这些特性的时候,也有不少优化技巧。比如:编译一个大型软件时,几条显式实例化指令就可能使编译速度提高几十倍;恰当地组合使用部分专门化和完全专门化,不但可以最优化程序的执行效率,还可以让同时使用多种不同参数实例化模板的软件体积显著减小……
运行时开销
运行时开销恐怕是程序员最关心的问题之一了。相对与传统C程序而言,C++中有可能引入额外运行时开销的新特性包括:
- 虚基类
- 虚函数
- RTTI(dynamic_cast和typeid)
- 异常
- 对象的构造和析构
关于其中第四点
而第五点对象的构造和析构开销也不总是存在。对于不需要初始化/销毁的类型,并没有构造和析构的开销,相反对于那些需要初始化/销毁的类型来说,即使用传统的C方式实现,也至少需要与之相当的开销。
对能够真正用于开发的编译器而言,C++本身就是使用C/汇编
C++之所以比C“低效”,其根本原因在于:由于对某些特性的实现方式及其开销不够了解,导致程序员在错误的位置使用了错误的特性。而这些错误基本都集中在:
·
·
其中第一点上文已经
为了说明RTTI、虚函数和虚基类的实现方式,首先给出一个实例及其具体实现(为了便于理解,这里故意忽略了一些无关紧要的优化):
图中虚箭头代表偏移,实箭头代表指针
由上图得到每种特性的运行时开销如下:
特性
时间开销
空间开销
RTTI
几次整形比较和一次取址操作(可能还会有1、2次整形加法)
每类型一个type_info对象(包括类型ID和类名称),典型情况下小于32字节
虚函数
一次整形加法和一次指针引用
每类型一个虚表,典型情况下小于32字节
每对象若干个(大部分情况下是一个)虚表指针,典型情况下小于8字节
虚基类
从直接虚继承的子类(例如上图中的
每类型一个虚基类表,典型情况下小于16字节
每对象若干虚基类表指针,典型情况下小于8字节
*
可见,关于老天爷“饿时掉馅饼、睡时掉老婆”等美好传说纯属谣言。但凡人工制品必不完美,总有设计上的取舍,有其适应的场合也有其不适用的地方。
C++中的每个特性,都是从程序员平时的生产生活中逐渐精化而来的。在不正确的场合使用它们必然会引起逻辑、行为和性能上的问题。对于上述特性,应该只在必要、合理的前提下才使用。
"dynamic_cast"
一般地讲,能用虚函数解决的问题就不要用
void
rotate(IN const CShape& iS)
{
}
以上代码用
虚函数是C++运行时多态特性中开销最小,也最常用的机制。虚函数的好处和作用这里不再多说,应当注意在对性能有苛刻要求的场合,或者需要频繁调用,对性能影响较大的地方(比如每秒钟
作为一种支持多继承的面向对象语言,虚基类有时是保证类层次结构正确的一种必不可少的手段。在需要频繁使用基类提供的服务,又对性能要求较高的场合,应该避免使用虚基类。
在基类中没有数据成员的场合,也可以解除使用虚基类。例如,在上图中,如果类
上述特性的空间开销一般都是可以接受的,当然也存在一些特例,比如:在存储布局需要和传统C结构兼容的场合、在考虑对齐的场合、在需要为一个本来很小的类同时实例化许多对象的场合等等。
最后
以上就是贤惠小天鹅为你收集整理的RTTI、虚函数和虚基类的开销分析及…的全部内容,希望文章能够帮你解决RTTI、虚函数和虚基类的开销分析及…所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复