没有模板代码膨胀的STL:四、一些讨论和个人心得
2015-05-11 07:36
323 查看
总目录
一、设计目标与实现思路
二、使用方法与注意事项
三、开发者指南
四、一些讨论和个人心得
前面3篇文章都是针对POD_STL项目本身的介绍。这篇文章则发散讨论下其他方面的内容。
全功能的去模板化STL是可能的吗?
有些人对POD_STL限制容器元素类型的做法颇有微词。但实际上,即使是标准STL也对容器元素类型有很多限制,而POD_STL只是放弃了对一部分很少使用的类型的支持。当然,人的欲望总是无穷的,我们不妨大胆想象一下:有没有可能实现一个与标准STL功能完全相同(暂时先不考虑allocator),但内部却没有模板代码膨胀的STL版本?
有些人会想:假如真有这种技术,世界上那么多聪明的程序员早就把它给实现了。怎么会把STL广被诟病的模板代码膨胀问题一直留到现在?
但我要说的是,实现这种STL版本还真是可能的。
在本系列第一篇《设计目标与实现思路》中,我介绍了关系型容器去模板化的一个技巧:将operator<比较运算符生成为实体函数,并在容器中使用函数指针来比较元素。如果把这个技巧更广泛的应用,就可以把元素类型的所有操作全变成函数指针调用。STL中对于元素的主要操作有:构造函数、copy构造函数、析构函数、operator=、operator<、operator==。只要在每个容器中保存这几个函数指针,就可以将所有内部操作全部去模板化。
下面是一个简单示例:
-cpp代码
既然此方法确实可行,为什么我不采用这种技术实现一个全功能的STL版本呢?——先抛开new运算符的使用和函数指针需要占用的空间不谈,我最担心的问题是:运行性能。
一旦像这样把所有元素操作都变成函数指针调用,那么在容器内部代码中就必须大量调用函数指针。且无论对于多么简单的类型都无法跳过这一过程!试想一下,在复制一个vector<char>容器时,对于每一个字节都调用一次函数指针来赋值是件多么傻的事情……即使char类型不需要析构函数,vector<char>容器在析构时也必须挨个对每个元素调用析构函数指针来尝试“析构”——即使这些指针指向的是空函数,函数调用开销也是存在的。
POD_STL项目所做的,是在内部去模板化的前提下,尽最大的努力来维持原有性能。使用memcpy复制元素,并省略掉析构函数调用是我能想到的性能最优的做法了。(其实对于某些操作,比如vector内成员的批量搬移,POD_STL的性能反而比标准STL更高,因为它只执行一次memcpy操作)
尽管如此,我仍然很期待有其他高手实现出全功能的无模板膨胀STL版本!毕竟多一种选择不是坏事,而且说不定它的实测性能并没有那么差。
心得体会
我喜欢C++,其中的各种高级模板特性让我非常着迷。这次对于STL源代码的重写让我更加深入了解了其内部实现,里面很多的模板编码技巧用得赏心悦目,看懂以后有茅塞顿开的感觉。如果你想深入学习C++和STL,我相信参与开发这个项目会是个很好的选择,对于编码能力会有很大提升。
但另一方面,在深入阅读STLport开源代码后,发现它也有很多缺点。既有考虑不周,性能不佳之处,也有功能上的BUG(见《STLport源代码中的一个BUG》)。因此,在学习代码“名作”长处的同时,也不应对其过于迷信。
POD_STL的全部代码已上传到GitHub开源平台,欢迎有兴趣的朋友参与开发和提出点评。
链接:https://github.com/Goalsum/POD_STL
一、设计目标与实现思路
二、使用方法与注意事项
三、开发者指南
四、一些讨论和个人心得
前面3篇文章都是针对POD_STL项目本身的介绍。这篇文章则发散讨论下其他方面的内容。
全功能的去模板化STL是可能的吗?
有些人对POD_STL限制容器元素类型的做法颇有微词。但实际上,即使是标准STL也对容器元素类型有很多限制,而POD_STL只是放弃了对一部分很少使用的类型的支持。当然,人的欲望总是无穷的,我们不妨大胆想象一下:有没有可能实现一个与标准STL功能完全相同(暂时先不考虑allocator),但内部却没有模板代码膨胀的STL版本?
有些人会想:假如真有这种技术,世界上那么多聪明的程序员早就把它给实现了。怎么会把STL广被诟病的模板代码膨胀问题一直留到现在?
但我要说的是,实现这种STL版本还真是可能的。
在本系列第一篇《设计目标与实现思路》中,我介绍了关系型容器去模板化的一个技巧:将operator<比较运算符生成为实体函数,并在容器中使用函数指针来比较元素。如果把这个技巧更广泛的应用,就可以把元素类型的所有操作全变成函数指针调用。STL中对于元素的主要操作有:构造函数、copy构造函数、析构函数、operator=、operator<、operator==。只要在每个容器中保存这几个函数指针,就可以将所有内部操作全部去模板化。
下面是一个简单示例:
-cpp代码
001 | typedef void (*_DataUnaryOp)( void * __data); |
002 | typedef void (*_DataBinaryOp)( void * __left, const void * __right); |
003 | typedef bool (*_DataBinaryPredicate)( const void * __left, const void * __right); |
004 |
005 | template < typename _Tp> |
006 | void _construct_fn( void * __data) |
007 | { |
008 | new (__data) _Tp(); // new的使用无法避免 |
009 | } |
010 |
011 | template < typename _Tp> |
012 | void _destruct_fn( void * __data) |
013 | { |
014 | static_cast <_Tp*>(__data)->~_Tp(); |
015 | } |
016 |
017 | template < typename _Tp> |
018 | void _copy_construct_fn( void * __new_obj, const void * __old_obj) |
019 | { |
020 | new (__new_obj) _Tp(*( static_cast < const _Tp*>(__old_obj))); // new的使用无法避免 |
021 | } |
022 |
023 | template < typename _Tp> |
024 | void _assign_fn( void * __new_obj, const void * __old_obj) |
025 | { |
026 | * static_cast <_Tp*>(__new_obj) = * static_cast < const _Tp*>(__old_obj); |
027 | } |
028 |
029 | template < typename _Tp> |
030 | bool _less_fn( const void * __left, const void * __right) |
031 | { |
032 | return * static_cast < const _Tp*>(__left) < * static_cast < const _Tp*>(__right); |
033 | } |
034 |
035 | template < typename _Tp> |
036 | bool _equal_fn( const void * __left, const void * __right) |
037 | { |
038 | return * static_cast < const _Tp*>(__left) == * static_cast < const _Tp*>(__right); |
039 | } |
040 |
041 | class _TestVectorBase |
042 | { |
043 | _DataUnaryOp __M_construct_fn; |
044 | _DataUnaryOp __M_destruct_fn; |
045 | _DataBinaryOp __M_copy_construct_fn; |
046 | _DataBinaryOp __M_assign_fn; |
047 | _DataBinaryPredicate __M_less_fn; |
048 | _DataBinaryPredicate __M_equal_fn; |
049 |
050 | void * __M_storage; |
051 |
052 | protected : |
053 | _TestVectorBase(_DataUnaryOp __construct_fn, _DataUnaryOp __destruct_fn, |
054 | _DataBinaryOp __copy_construct_fn, _DataBinaryOp __assign_fn, |
055 | _DataBinaryPredicate __less_fn, _DataBinaryPredicate __M_equal_fn) |
056 | : __M_construct_fn(__construct_fn), __M_destruct_fn(__destruct_fn), |
057 | __M_copy_construct_fn(__copy_construct_fn), __M_assign_fn(__assign_fn), |
058 | __M_less_fn(__less_fn), __M_equal_fn(__M_equal_fn) |
059 | {} |
060 |
061 | void _M_push_back( void * __element) |
062 | { |
063 | __M_storage = malloc (100); |
064 | __M_copy_construct_fn(__M_storage, __element); // 通过函数指针调用了copy构造函数,等同于new(__M_storage) _Tp(__element) |
065 | } |
066 | }; |
067 |
068 | template < typename _Tp> |
069 | class _TestVector : public _TestVectorBase |
070 | { |
071 | public : |
072 | _TestVector() : _TestVectorBase(_construct_fn<_Tp>, _destruct_fn<_Tp>, _copy_construct_fn<_Tp>, _assign_fn<_Tp>, _less_fn<_Tp>, _equal_fn<_Tp>){} |
073 |
074 | void push_back(_Tp __element) |
075 | { |
076 | _M_push_back(&__element); // 不再需要传入元素大小 |
077 | } |
078 | }; |
079 |
080 | class _TestClass |
081 | { |
082 | int x; |
083 |
084 | public : |
085 | _TestClass(){} |
086 | _TestClass( const _TestClass& __other) : x(__other.x) |
087 | { |
088 | cout << "copy constructor executed!" << endl; |
089 | } |
090 |
091 | bool operator <( const _TestClass& __other) const { return x < __other.x; } |
092 | bool operator ==( const _TestClass& __other) const { return x == __other.x; } |
093 | }; |
094 |
095 | int main( int argc, _TCHAR* argv[]) |
096 | { |
097 | _TestVector<_TestClass> a; |
098 | a.push_back(_TestClass()); |
099 | return 0; |
100 | } |
一旦像这样把所有元素操作都变成函数指针调用,那么在容器内部代码中就必须大量调用函数指针。且无论对于多么简单的类型都无法跳过这一过程!试想一下,在复制一个vector<char>容器时,对于每一个字节都调用一次函数指针来赋值是件多么傻的事情……即使char类型不需要析构函数,vector<char>容器在析构时也必须挨个对每个元素调用析构函数指针来尝试“析构”——即使这些指针指向的是空函数,函数调用开销也是存在的。
POD_STL项目所做的,是在内部去模板化的前提下,尽最大的努力来维持原有性能。使用memcpy复制元素,并省略掉析构函数调用是我能想到的性能最优的做法了。(其实对于某些操作,比如vector内成员的批量搬移,POD_STL的性能反而比标准STL更高,因为它只执行一次memcpy操作)
尽管如此,我仍然很期待有其他高手实现出全功能的无模板膨胀STL版本!毕竟多一种选择不是坏事,而且说不定它的实测性能并没有那么差。
心得体会
我喜欢C++,其中的各种高级模板特性让我非常着迷。这次对于STL源代码的重写让我更加深入了解了其内部实现,里面很多的模板编码技巧用得赏心悦目,看懂以后有茅塞顿开的感觉。如果你想深入学习C++和STL,我相信参与开发这个项目会是个很好的选择,对于编码能力会有很大提升。
但另一方面,在深入阅读STLport开源代码后,发现它也有很多缺点。既有考虑不周,性能不佳之处,也有功能上的BUG(见《STLport源代码中的一个BUG》)。因此,在学习代码“名作”长处的同时,也不应对其过于迷信。
POD_STL的全部代码已上传到GitHub开源平台,欢迎有兴趣的朋友参与开发和提出点评。
链接:https://github.com/Goalsum/POD_STL
相关文章推荐
- 没有模板代码膨胀的STL:一、设计目标与实现思路
- 没有模板代码膨胀的STL:二、使用方法与注意事项
- 没有模板代码膨胀的STL:三、开发者指南
- 个人对一些社交平台的心得
- STL + c++ + 模板 + 重要思维 + 基础算法+ 经典算法 + 经典实例 + 编程总结+ 心得+ 入门必会 + 知识点汇总。+string +dfs +bfs等重要算法
- 谈谈个人对插件及框架设计的一些心得
- 一个问题,两人讨论,几行代码,一些启发
- 代码的个人心得
- 任何javascript框架(如jQuery)的代码是藏不住的,都是完全暴露源码的,因为JavaScript不像java一样,java的一些代码被封装进jar了,JavaScript没有封装
- 防止模板代码膨胀
- 个人博客作业2 - 代码规范讨论与个人项目代码审查
- 阅读代码的一些心得体会
- 对 JimmyZhang 老师的文章《项目代码风格要求》的一些个人观点
- [个人心得]渗透测试的一些总结
- Servlet的一些技巧&模板代码
- MapXtreme 2005 学习心得 一些基础函数代码(四)
- 一个问题,两人讨论,几行代码,一些启发
- 写给那些大学不怎么用功的我们:学习java的一些心得、对java发展的看法和一些代码
- 使用Git进行代码管理心得------------个人练习
- 一款不错的html5网站模板案例代码下载,用于开发个人网站,兼容手机与PC