分享
 
 
 

翻译:Effective C++, 3rd Edition, Item 44: 从 templates(模板)中分离出 parameter-independent(参数无关)的代码(下)

王朝c/c++·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

(点击此处,接上篇)

一个可替换方案是让 SquareMatrixBase 存储一个指向矩阵的值的内存区域的指针。而且一旦它存储了这个指针,它同样也可以存储矩阵大小。最后得到的设计大致就像这样:

template<typename T>

class SquareMatrixBase {

protected:

SquareMatrixBase(std::size_t n, T *pMem) // store matrix size and a

: size(n), pData(pMem) {} // ptr to matrix values

void setDataPtr(T *ptr) { pData = ptr; } // reassign pData

...

private:

std::size_t size; // size of matrix

T *pData; // pointer to matrix values

};

这样就是让 derived classes(派生类)决定如何分配内存。某些实现可能决定直接在 SquareMatrix object 内部存储矩阵数据:

template<typename T, std::size_t n>

class SquareMatrix: private SquareMatrixBase<T> {

public:

SquareMatrix() // send matrix size and

: SquareMatrixBase<T>(n, data) {} // data ptr to base class

...

private:

T data[n*n];

};

这种类型的 objects 不需要 dynamic memory allocation(动态内存分配),但是这些 objects 本身可能会非常大。一个可选方案是将每一个矩阵的数据放到 heap(堆)上:

template<typename T, std::size_t n>

class SquareMatrix: private SquareMatrixBase<T> {

public:

SquareMatrix() // set base class data ptr to null,

: SquareMatrixBase<T>(n, 0), // allocate memory for matrix

pData(new T[n*n]) // values, save a ptr to the

{ this->setDataPtr(pData.get()); } // memory, and give a copy of it

... // to the base class

private:

boost::scoped_array<T> pData; // see Item 13 for info on

}; // boost::scoped_array

无论数据存储在哪里,从膨胀的观点来看关键的结果在于:现在 SquareMatrix 的许多——也许是全部—— member functions(成员函数)可以简单地 inline 调用它的 base class versions(基类版本),而这个版本是与其它所有持有相同数据类型的矩阵共享的,而无论它们的大小。与此同时,不同大小的 SquareMatrix objects 是截然不同的类型,所以,例如,即使 SquareMatrix<double, 5> 和 SquareMatrix<double, 10> objects 使用 SquareMatrixBase<double> 中同样的 member functions(成员函数),也没有机会将一个 SquareMatrix<double, 5> object 传送给一个期望一个 SquareMatrix<double, 10> 的函数。很好,不是吗?

很好,是的,但不是免费的。将矩阵大小硬性固定在其中的 invert 版本很可能比将大小作为一个函数参数传入或存储在 object 中的共享版本能产生更好的代码。例如,在 size-specific(特定大小)的版本中,sizes(大小)将成为 compile-time constants(编译期常数),因此适用于像 constant propagation 这样的优化,包括将它们作为 immediate operands(立即操作数)嵌入到生成的指令中。在 size-independent version(大小无关版本)中这是不可能做到的。

另一方面,将唯一的 invert 的版本用于多种矩阵大小缩小了可执行码的大小,而且还能缩小程序的 working set(工作区)大小以及改善 instruction cache(指令缓存)中的 locality of reference(引用的局部性)。这些能使程序运行得更快,超额偿还了失去的针对 invert 的 size-specific versions(特定大小版本)的任何优化。哪一个效果更划算?唯一的分辨方法就是在你的特定平台和典型数据集上试验两种方法并观察其行为。

另一个效率考虑关系到 objects 的大小。如果你不小心,将函数的 size-independent 版本(大小无关版本)上移到一个 base class(基类)中会增加每一个 object 的整体大小。例如,在我刚才展示的代码中,即使每一个 derived class(派生类)都已经有了一个取得数据的方法,每一个 SquareMatrix object 都还有一个指向它的数据的指针存在于 SquareMatrixBase class 中,这为每一个 SquareMatrix object 至少增加了一个指针的大小。通过改变设计使这些指针不再必需是有可能的,但是,这又是一桩交易。例如,让 base class(基类)存储一个指向矩阵数据的 protected 指针导致在 Item 22 中描述的封装性的降低。它也可能导致资源管理复杂化:如果 base class(基类)存储了一个指向矩阵数据的指针,但是那些数据既可以是动态分配的也可以是物理地存储于 derived class object(派生类对象)之内的(就像我们看到的),它如何决定这个指针是否应该被删除?这样的问题有答案,但是你越想让它们更加精巧一些,它就会变成更复杂的事情。在某些条件下,少量的代码重复就像是一种解脱。

本 Item 只讨论了由于 non-type template parameters(非类型模板参数)引起的膨胀,但是 type parameters(类型参数)也能导致膨胀。例如,在很多平台上,int 和 long 有相同的二进制表示,所以,可以说,vector<int> 和 vector<long> 的 member functions(成员函数)很可能是相同的——膨胀的恰到好处的解释。某些连接程序会合并同样的函数实现,还有一些不会,而这就意味着在一些环境上一些模板在 int 和 long 上都被实例化而能够引起代码重复。类似地,在大多数平台上,所有的指针类型有相同的二进制表示,所以持有指针类型的模板(例如,list<int*>,list<const int*>,list<SquareMatrix<long, 3>*> 等)应该通常可以使用每一个 member function(成员函数)的单一的底层实现。典型情况下,这意味着与 strongly typed pointers(强类型指针)(也就是 T* 指针)一起工作的 member functions(成员函数)可以通过让它们调用与 untyped pointers(无类型指针)(也就是 void* 指针)一起工作的函数来实现。一些标准 C++ 库的实现对于像 vector,deque 和 list 这样的模板就是这样做的。如果你关心起因于你的模板的代码膨胀,你可能需要用同样的做法开发模板。

Things to Remember

templates(模板)产生多个 classes 和多个 functions,所以一些不依赖于 template parameter(模板参数)的模板代码会引起膨胀。non-type template parameters(非类型模板参数)引起的膨胀常常可以通过用 function parameters(函数参数)或 class data members(类数据成员)替换 template parameters(模板参数)而消除。type parameters(类型参数)引起的膨胀可以通过让具有相同的二进制表示的实例化类型共享实现而减少。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有