当前位置: 首页 > news >正文

Item44--将与参数无关的代码抽离 templates

在使用模板时,编译器会为每一组不同的模板参数生成一份独立的实例化代码。如果这些代码中存在与参数无关的部分,就会导致生成的二进制文件冗余,增加内存占用和指令缓存压力。


1. 核心问题:代码膨胀 (Code Bloat)

模板虽然能减少源代码的重复,但如果不加节制,会导致编译后的二进制代码重复。

举个例子:固定大小的矩阵

假设我们要写一个表示正方形矩阵的类,其中矩阵大小是一个非类型模板参数(non-type template parameter):

template<typename T, std::size_t n>
class SquareMatrix {
public:void invert(); // 求逆矩阵
};// 使用
SquareMatrix<double, 5> sm1;
SquareMatrix<double, 10> sm2;

问题在于:

编译器会为 SquareMatrix<double, 5>::invert 和 SquareMatrix<double, 10>::invert 生成两份几乎完全相同的机器码。虽然矩阵大小 $n$ 不同,但求逆算法的逻辑(如高斯消元)对于 double 类型通常是一致的。这种由非类型参数引起的重复就是代码膨胀。


2. 解决方案:因式分解 (Factorization)

解决思路类似于代数中的公因式提取:将不依赖于特定模板参数的代码提取到基类或独立函数中。

第一步:引入带有参数的基类

我们将大小 $n$ 从模板参数改为函数参数,并放入一个基类中:

template<typename T>
class SquareMatrixBase {
protected:void invert(std::size_t matrixSize); // 提取出来的公共逻辑
};template<typename T, std::size_t n>
class SquareMatrix: private SquareMatrixBase<T> {
private:using SquareMatrixBase<T>::invert; // 避免遮掩基类名称
public:void invert() { this->invert(n); } // 调用基类版本,传入大小
};

这样,无论 $n$ 是 5 还是 10,底层都只调用同一份 SquareMatrixBase<double>::invert 代码。

第二步:处理数据指针

上面的 invert 仍然需要知道矩阵数据在哪里。我们不希望在基类中写死数组大小,因此可以使用指针:

template<typename T>
class SquareMatrixBase {
protected:SquareMatrixBase(std::size_t n, T* pMem) : size(n), pData(pMem) {}void setDataPtr(T* ptr) { pData = ptr; }std::size_t size;T* pData; // 矩阵数据的指针void invert() { /* 使用 size 和 pData 进行计算 */ }
};template<typename T, std::size_t n>
class SquareMatrix: private SquareMatrixBase<T> {
public:SquareMatrix() : SquareMatrixBase<T>(n, data) {}
private:T data[n*n]; // 数据存储在派生类中
};

3. 两种膨胀来源的应对策略

条款 44 主要讨论了两种导致膨胀的情况:

A. 非类型模板参数 (Non-type Parameters)

如上面的 size_t n

  • 做法: 将该参数替换为函数参数或类成员变量。
  • 收益: 减少因数值不同导致的实例化副本。

B. 类型参数 (Type Parameters)

T。虽然不同类型(如 intdouble)通常需要不同的二进制代码,但某些类型在底层表示上是相同的。

  • 例子: 很多平台上,所有指针类型的底层实现是完全一样的(如 vector<int*>vector<Shape*>)。
  • 做法: 某些高级实现(如早期 STL)会让所有指针类型的模板共用一个 void* 的实现版本,通过强转来保证类型安全。

4. 权衡与代价

虽然抽离代码能显著减小二进制体积,但也存在权衡:

  1. 性能微降: 抽离后的代码可能无法利用编译器针对特定数值(如固定的 $5 \times 5$ 循环)进行的硬编码优化(Inline 或 Loop Unrolling)。
  2. 复杂性: 引入基类增加了代码层级,数据指针的管理也需要更加小心(防止野指针)。
  3. 内存开销: 在基类中存储指针或大小会略微增加每个对象的内存占用。

5. 核心结论

  • 警惕膨胀: 模板会产生重复的代码和数据。
  • 共性提取: 如果发现多个模板实例化后的行为基本一致,应通过共性分析将无关代码移入基类。
  • 非类型参数转变量: 将非类型模板参数(如 $n$)改为构造函数参数或成员变量,往往是消除冗余的第一步。
http://www.jsqmd.com/news/112223/

相关文章:

  • Item43--处理模板化基类内的名称
  • 2025年选购指南:山东口碑好的阿胶厂家深度解析,非遗膏方/阿胶类产品/阿胶/膏方类产品/阿胶糕/膏方/阿胶产品/阿胶类阿胶采购找哪家 - 品牌推荐师
  • 2025年特种调节阀领域十大知名厂家盘点,气动三通调节阀/自力式调节阀/气动调节阀/美标调节阀/特种调节阀/调节阀调节阀生产商排行榜 - 品牌推荐师
  • 2025年特种调节阀领域十大知名厂家盘点,气动三通调节阀/自力式调节阀/气动调节阀/美标调节阀/特种调节阀/调节阀调节阀生产商排行榜 - 品牌推荐师
  • 房叮咚订房平台深度解析:“用户出价,酒店抢单”如何颠覆传统酒店预订? - 资讯焦点
  • 房叮咚订房平台深度解析:“用户出价,酒店抢单”如何颠覆传统酒店预订? - 资讯焦点
  • 2025年方圆螺旋焊管直销厂家权威推荐榜单:螺旋管防腐/螺旋钢管/螺旋管涂塑源头厂家精选 - 品牌推荐官
  • scratch怎么做游戏?看完这篇你就懂了
  • 2025年12月坦克链,无尘坦克链,工程塑料坦克链厂商推荐:聚焦企业综合实力与核心竞争力 - 品牌鉴赏师
  • 1N4007在小电流的压降
  • 2025昆明珠宝回收推荐案例调查-昆明钱鑫珠宝甄选/黄金回收门店/珠宝回收门店/翡翠回收门店 - charlieruizvin
  • 2025年高精度固体密度仪权威推荐榜单:高精度固体密度计/高精度固体电子密度计/固体电子比重测试仪源头厂家精选 - 品牌推荐官
  • imgui-python
  • 2025 年辣味零食品牌推荐排行榜:重口味解馋小零食推荐及挑选指南和选购建议 - AIEO
  • 搞懂 Java 中的 VO、BO、PO、DTO、DO
  • 表连接
  • 搞懂 Java 中的 VO、BO、PO、DTO、DO
  • 2025年12月高速坦克链,无尘坦克链,尼龙坦克链公司推荐:行业测评与选择指南 - 品牌鉴赏师
  • Python中的len查询字节函数
  • Python中的len查询字节函数
  • 广东程序园科技有限公司深度解析:一家如何以技术驱动重塑酒旅生态的科技企业 - 资讯焦点
  • 2025深圳旧房改造公司权威推荐! - 品牌评测官
  • 2025年隔热条生产厂家哪家质量可靠?五大品质之选厂商推荐全解析 - 工业品牌热点
  • 告别格式烦恼!Acrobat Pro DC 2024 破解版下载安装一键搞定 PDF 编辑 / 转换 / 签名
  • 机器人轴承厂家十大排名推荐 RV减速机轴承/谐波减速机轴承/交叉滚子轴承/柔性轴承/薄壁角接触球轴承/行星架 - 小张666
  • 2025年12月拖链,电缆拖链,工程拖链公司推荐:行业测评与选择指南 - 品牌鉴赏师
  • 2025年皮带线定制厂家权威推荐榜单:自动化输送线/链板线/同步带源头厂家精选 - 品牌推荐官
  • 2025年度热解炉口碑好的生产商、靠谱服务商及价格合理加工厂推荐 - mypinpai
  • 2025-2026北京离婚子女抚养法律服务白皮书:专业律师测评与选择指南 - 老周说教育
  • 2025-2026北京离婚子女抚养法律服务白皮书:专业律师测评与选择指南 - 老周说教育