当前位置:天才代写 > tutorial > C语言/C++ 教程 > More Effective C++:制止缺省结构函数

More Effective C++:制止缺省结构函数

2017-11-06 08:00 星期一 所属: C语言/C++ 教程 浏览:356

副标题#e#

缺省结构函数(指没有参数的结构函数)在C++语言中是一种让你无中生有的要领。结构函数能初始化工具,而缺省结构函数则可以倒霉用任安在成立工具时的外部数据就能初始化工具。有时这样的要领是不错的。譬喻一些行为特性与数字相仿的工具被初始化为空值或不确定的值也是公道的,尚有好比链表、哈希表、图等等数据布局也可以被初始化为空容器。

但不是所有的工具都属于上述范例,对付许多工具来说,倒霉用外部数据举办完全的初始化是不公道的。好比一个没有输入姓名的地点簿工具,就没有任何意义。在一些公司里,所有的设备都必需标有一个公司ID号码,所以在成立工具以模子化一个设备时,不提供一个符合的ID号码,所成立的工具就基础没有意义。

在一个完美的世界里,无需任何数据即可成立工具的类可以包括缺省结构函数,而需要数据来成立工具的类则不能包括缺省结构函数。唉!但是我们的现实世界不是完美的,所以我们必需思量更多的因素。出格是假如一个类没有缺省结构函数,就会存在一些利用上的限制。

请思量一下有这样一个类,它暗示公司的设备,这个类包括一个公司的ID代码,这个ID代码被强制做为结构函数的参数:

class EquipmentPiece {
 public:
  EquipmentPiece(int IDNumber);
  ...
};

因为EquipmentPiece类没有一个缺省结构函数,所以在三种环境下利用它,就会碰着问题。第一中环境是成立数组时。一般来说,没有一种步伐能在成立工具数组时给结构函数通报参数。所以在凡是环境下,不行能成立EquipmentPiece工具数组:

EquipmentPiece bestPieces[10]; // 错误!没有正确挪用
// EquipmentPiece 结构函数
EquipmentPiece *bestPieces =
new EquipmentPiece[10]; // 错误!与上面的问题一样

不外照旧有三种要领能回避开这个限制。对付利用非堆数组(non-heap arrays)(即不在堆中给数组分派内存。译者注)的一种办理要领是在数组界说时提供须要的参数:


#p#副标题#e# int ID1, ID2, ID3, ..., ID10; // 存储设备ID号的
// 变量
...
EquipmentPiece bestPieces[] = { // 正确, 提供告终构
 EquipmentPiece(ID1), // 函数的参数
 EquipmentPiece(ID2),
 EquipmentPiece(ID3),
 ...,
 EquipmentPiece(ID10)
};

不外很遗憾,这种要领不能用在堆数组(heap arrays)的界说上。一个更通用的办理要领是操作指针数组来取代一个工具数组:

typedef EquipmentPiece* PEP; // PEP 指针指向
//一个EquipmentPiece工具
PEP bestPieces[10]; // 正确, 没有挪用结构函数
PEP *bestPieces = new PEP[10]; // 也正确

在指针数组里的每一个指针被从头赋值,以指向一个差异的EquipmentPiece工具:

for (int i = 0; i < 10; ++i)
bestPieces[i] = new EquipmentPiece( ID Number );

不外这中要领有两个缺点,第一你必需删除数组里每个指针所指向的工具。假如你忘了,就会产生内存泄漏。第二增加了内存分派量,因为正如你需要空间来容纳EquipmentPiece工具一样,你也需要空间来容纳指针。

假如你为数组分派raw memory,你就可以制止挥霍内存。利用placement new要领在内存中结构EquipmentPiece工具:

// 为巨细为10的数组 分派足够的内存
// EquipmentPiece 工具; 具体环境请拜见条款8
// operator new[] 函数
void *rawMemory =
operator new[](10*sizeof(EquipmentPiece));
// make bestPieces point to it so it can be treated as an
// EquipmentPiece array
EquipmentPiece *bestPieces =
static_cast(rawMemory);
// construct the EquipmentPiece objects in the memory
// 利用"placement new" (拜见条款8)
for (int i = 0; i < 10; ++i)
new (&bestPieces[i]) EquipmentPiece( ID Number );

留意你仍旧得为每一个EquipmentPiece工具提供结构函数参数。这个技能(也称为数组到指针的思想array-of-pointers)答允你在没有缺省结构函数的环境下成立一个工具数组。它没有绕过对结构函数参数的需求,实际上也做不到。假如能做到的话,就不能担保工具被正确初始化。

#p#副标题#e#

利用placement new的缺点除了是大大都措施员对它不熟悉外(能利用它就更难了),尚有就是当你不想让它继承存在利用时,必需手动挪用数组工具的析构函数,挪用操纵符delete[]来释放 raw memory:

// 以与结构bestPieces工具相反的顺序
// 解构它。
for (int i = 9; i >= 0; --i)
bestPieces[i].~EquipmentPiece();
// deallocate the raw memory
operator delete[](rawMemory);

#p#分页标题#e#

假如你健忘了这个要求或没有用这个数组删除要领,那么你措施的运行将是不行预测的。这是因为直接删除一个不是用new操纵符来分派的内存指针,其功效没有被界说的。

delete [] bestPieces; // 没有界说! bestPieces
//不是用new操纵符分派的。

有关new、placement new和它们如何与结构函数、析构函数一起利用的更多信息,请见条款8。

对付类里没有界说缺省结构函数所造成的第二个问题是它们无法在很多基于模板(template-based)容器类里利用。因为实例化一个模板时,模板的范例参数应该提供一个缺省结构函数,这是一个常见的要求。这个要求老是来自于模板内部,被成立的模板参数范例数组里。譬喻一个数组模板类:

template
class Array {
 public:
  Array(int size);
  ...
 private:
  T *data;
};
template
Array::Array(int size)
{
 data = new T[size]; // 为每个数组元素
 ... //依次挪用 T::T()
}

在大都环境下,通过仔细设计模板可以杜绝对缺省结构函数的需求。譬喻尺度的vector模板(生成一个雷同于可扩展数组的类)对它的范例参数没有必需有缺省结构函数的要求。不幸的是,许多模板类没有以仔细的立场去设计,这样没有缺省结构函数的类就不能与很多模板兼容。当C++措施员深入了解了模板设计今后,这样的问题应该不再那么突出了。这会花多长时间,完全在于小我私家的造化。

#p#副标题#e#

最后讲一下在设计虚基类时所面对的是要提供缺省结构函数照旧不提供缺省结构函数的两难决定。不提供缺省结构函数的虚基类很难与其举办事情。因为险些所有的派生类在实例化时斗必需给虚基类结构函数提供参数。这就要求所有从没有缺省结构函数的虚基类担任下来的派生类(无论有多远)都必需知道并领略提供应虚基类结构函数的参数寄义。派生类的作者是不会企盼和喜欢这种划定的。

因为这些强加于没有缺省结构函数的类上的各种限制,一些人认为所有的类都应该有缺省结构函数,纵然缺省结构函数没有足够的数据来初始化一个工具。好比这个原则的拥护者会这样修改EquipmentPiece类:

class EquipmentPiece {
 public:
  EquipmentPiece( int IDNumber = UNSPECIFIED);
  ...
 private:
  static const int UNSPECIFIED; // ID值不确定。
};

这答允这样成立EquipmentPiece工具

EquipmentPiece e; //这样正当

这样的修改使得其他成员函数变得巨大,因为不再能确保EquipmentPiece工具举办有意义的初始化。假设它成立一个因没有ID而没有意义的EquipmentPiece工具,那么大大都成员函数必需检测ID是否存在。假如不存在ID,它们将必需知道怎么犯的错误。不外这常常是不明了的,许多代码实现什么也没有提供,只是抛出一个异常或挪用一个函数终止措施。当这种景象产生时,很难说提供缺省结构函数而放弃了一种担保机制这种做法是否能提高软件的总体质量。

提供无意义的缺省结构函数也会影响类的事情效率。假如成员函数必需测试所有的部门是否都被正确地初始化,那么这些函数的挪用者就得为此支付更多的时间。并且还得支付更多的代码,因为这使得可执行文件或库变得更大。它们也得在测试失败的处所安排代码来处理惩罚错误。假如一个类的结构函数可以或许确保所有的部门被正确初始化,所有这些弊病都可以或许制止。缺省结构函数一般不会提供这种担保,所以在它们能使类变得没有意义时,只管去制止利用它们。利用这种类简直有一些限制,可是当你利用它时,它也给你提供了一种担保,你能相信这个类被正确地成立和高效地实现。

 

    关键字:

天才代写-代写联系方式