Item 44 与模板参数无关的代码

阅读更多

模板可以节省时间,减少代码的重复。
假设有20个类,每个类15个成员函数。那么可以用一个类模板来定义,然后由编译器去实例化所需要的类。
模板类的成员函数只在用到的时候才实例化。

过度使用模板会导致目标代码的膨胀。要通过共性/异性分析防止这种事情发生。

// n*n矩阵,元素类型为T template class SquareMatrix { public: ... void invert(); // 求逆矩阵 }; SquareMatrix sm1; sm1.invert(); SquareMatrix sm2; sm2.invert();

两份invert,很明显的代码重复。修改之后:

template class SquareMatrixBase { // 尺寸无关的矩阵基类 protected: SquareMatrixBase(std::size_t n, T *pMem) : size(n), pData(pMem) {} void setDataPtr(T *ptr) { pData = ptr; } ... void invert(std::size_t size); // 通用的求逆矩阵算法 private: std::size_t size; T *pData; }; template class SquareMatrix: private SquareMatrixBase { private: using SquareMatrixBase::invert; // 避免隐藏基类的invert。见Item 33 public: ... void invert() { this->invert(n); } // 内联函数,调用基类的invert SquareMatrix() : SquareMatrixBase(n, data) {} private: T data[n*n]; };

1> SquareMatrixBase是为了避免代码膨胀而定义的,所以其invert声明为protected,而非public。
2> 因为使用了内联,所以派生类调用基类的invert时间成本为零。
3> 必须使用this指针去调用基类的invert。详见Item 43。
4> 继承关系使用private,表示基类只是为了辅助实现而设计的。
5> 存储数据的指针,要传给基类,以操作数据。
6> 如果觉得 data[n*n] 会让类变大,可以使用 boost::scoped_array pData 来申请堆上内存。

● 讨论
1> 把size写死到invert里可能会有编译器优化;把size当参数传给invert可以减小目标代码,从而提高执行效率。哪一个更好,这个要都试过才知道。
2> 把invert移到基类,会增大对象的体积。比如上面的例子,至少每个基类要有个指针吧。对指针的生存期的管理又增加了使用复杂度。


● 对type parameter的优化
1> 前面讨论的都是non-type parameter,而如int、long这些所谓的type parameter也可能导致代码膨胀。比如某些平台int和long一样,一些linker却不理会,于是制造出两份,造成了重复。
2> 大多数平台,对于不同类型的指针,其实二进制表示是完全相同的。这也可以用来优化:成员函数使用强类型指针,内部实现使用void无类型指针函数完成工作。

你可能感兴趣的:(算法,工作)