Curiously Recurring Template Pattern在ATL和Boost中被广泛的使用, 这种模式常常被作为c++中动态绑定的一种优化方案,从而避免使用C++动态绑定引起的在时间和空间上面的cost。
目前所有的C++编译器都是基于vTable实现C++的动态绑定,其代价是一个所有对象共享的虚函数表,每个对象增加一个额外的4/8字节的虚函数表指针,以及在函数调用时候至少经过两个指针间接寻址才能够完成的函数调用。CRTP的主要机制是将动态绑定中运行时期执行的函数选择提前到编译时去执行,从而避免了动态绑定在空间和时间上引起的损失。
CRTP对每个对象中虚函数表指针的优化切实可见,尤其在创建大量C++对象的情况下; 而对性能的优化则是众说纷纭,《深度探索c++对象模型》在4.3章中提到基于虚函数表的动态绑定会降低4%~11%的效率,这篇文件则更加详细的介绍了编译器、编译器的优化等级以及操作系统对性能测试结果的影响。
下面的测试结果都是基于gist中的这段代码完成的,编译器版本是vs2008,操作系统是运行在Fusion中的windows 10. 程序运行的时间并没有太大的参考价值,重点是使用动态绑定和CRTP时数据的相对变化.
-
Disable Optimization. /O2
v1 compute time = 0.0650303 v2 compute time = 0.126805
-
Enable Optimization. /O2 + /Ob2
v1 compute time = 0.0385662 v2 compute time = 0.00403758
可以看出.
- 编译器对基于vTable的虚函数无法进行inline的优化,而编译器可以对CRTP实现的函数进行inline的优化.
- 如果未启用优化CRTP比动态绑定反而更慢,其原因是CRTP会导致callstack变长;
- CRTP可以比基于vTable实现的虚函数或动态绑定非常显著的提高性能。