【effective C++】条款四十四:将与参数无关的代码抽离 templates
文章目录Effective C 条款44将与参数无关的代码抽离templates核心思想对抗代码膨胀规则详解与示例规则1不与造成膨胀的参数相依规则2处理非类型参数造成的膨胀规则3处理类型参数造成的膨胀优化带来的权衡总结请记住1. Templates 生成多个 classes 和多个函数所以任何 template 代码都不该与某个造成膨胀的 template 参数产生相依关系。2. 因非类型模板参数non-type template parameters)而造成的代码膨胀往往可消除做法是以函数参数或 class 成员变量替换 template 参数3. 因类型参数type parameters而造成的代码膨胀往往可降低做法是让带有完全相同二进制表述(binary representations的具现类型instantiation types共享实现码toolName: CompactFakestatus: successEffective C 条款44将与参数无关的代码抽离templates核心思想对抗代码膨胀条款44的核心目标是避免因模板使用不当而引发的代码膨胀。模板本质上是一种代码生成器编译会为每一组不同的模板参数生成一份独立的代码。如果这些代码中存在与模板参数无关的部分就会造成冗余。规则详解与示例规则1不与造成膨胀的参数相依这是总纲。它提醒你要有意识地去审视模板代码识别出哪些部分其实并不依赖于那些会引发多种实例化的参数无论是类型参数还是非类型参数。规则2处理非类型参数造成的膨胀非类型参数指整数、枚举、指针等具体值而非类型。问题一个矩阵模板尺寸作为非类型参数。Matrixint, 5和Matrixint, 10会导致编译器生成两个几乎完全相同的invert函数仅仅因为尺寸常量不同。// 膨胀的写法templatetypenameT,size_t nclassSquareMatrix{public:voidinvert(){/* 算法实现但循环次数依赖于 n */}};解法将与参数无关的代码抽离template。具体做法是引入一个基类将尺寸作为运行时参数传递。// 1. 创建与尺寸无关的基类templatetypenameTclassSquareMatrixBase{protected:// 尺寸不再是模板参数而是函数参数voidinvert(size_t matrixSize){/* 算法实现 */}};// 2. 子类调用基类实现templatetypenameT,size_t nclassSquareMatrix:privateSquareMatrixBaseT{// 私有继承表示用...来实现private:usingSquareMatrixBaseT::invert;// 防止名称遮掩public:// 子类的invert只是封装一下调用基类的实现voidinvert(){this-invert(n);}// 注意用this-确保找到基类名称};这样所有SquareMatrixint, n对象都共享同一份SquareMatrixBaseint::invert代码从根本上消除了因尺寸n不同造成的膨胀。规则3处理类型参数造成的膨胀类型参数造成的膨胀更隐蔽但同样可以优化。问题在某些平台上int*和long*的底层二进制表示完全相同但Listint*和Listlong*会实例化成两份完全独立的代码。解法让具有相同二进制表示的类型共享实现码。常见的做法是让模板类内部使用一个以void*进行操作的通用实现然后通过类型安全的接口封装给用户。// 1. 通用实现操作void*classGenericPointerList{protected:voidinsert(void*p);// ...};// 2. 类型安全模板接口templatetypenameTclassPointerList:privateGenericPointerList{public:voidinsert(T*p){GenericPointerList::insert(static_castvoid*(p));}// ...};这样PointerListint*和PointerListlong*虽然类型不同但底层的实现都共用GenericPointerList的代码避免了膨胀。优化带来的权衡需要注意的是这些优化技术并非没有代价。以非类型参数的优化为例优点显著减少代码体积可能提升指令缓存命中率使程序运行更快。代价将编译期常量如模板参数n变为运行期参数或成员变量编译器可能无法进行像常量传播这样的深度优化理论上可能降低代码运行效率。同时引入基类可能会增加对象大小例如基类中存储数据指针。因此是否要进行这类优化需要根据实际情况权衡。如果代码体积是瓶颈或者矩阵尺寸很大且算法复杂那么优化利大于弊。如果是对性能极其敏感的循环保留编译期优化可能是更好的选择。总结简单来说条款44教你像优化重复函数一样去优化模板树立意识时刻警惕模板可能引起的代码膨胀。针对非类型参数考虑能否把它变成函数参数或成员变量从而将代码实现下沉到与参数无关的基类中。针对类型参数检查是否有二进制表示相同的类型特别是指针可以考虑让它们共享同一份底层实现。在学习C模板时理解这种空间与效率的权衡是非常重要的成长。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2409244.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!