没有合适的资源?快使用搜索试试~ 我知道了~
首页C++高效编程指南:中文版精华提炼
"《More Effective C++ 简体中文版》是一本由Scott Meyers编著的专业级C++编程指南,中文版由侯捷担任译序和导读,涵盖了C++语言的深度实践技巧。本书分为多个部分,包括基础议题、运算符、异常处理、效率优化以及技巧等内容。 在基础议题中,作者详细解释了指针与引用的区别,强调了C++风格的类型转换的重要性,并提醒读者避免对数组使用多态和创建无用的缺省构造函数。这些概念有助于程序员编写更清晰、更高效代码。 运算符章节中,作者指导读者注意定义类型转换函数时的谨慎态度,区分自增和自减操作符的前缀和后缀形式,同时警告不要重载特殊逻辑运算符如“&&”、“||”和“,”,以及深入理解内存管理操作符NEW和DELETE的不同含义。 异常处理是书中重要部分,作者提倡使用析构函数防止资源泄漏,提醒在构造函数中避免资源泄漏,并指出异常信息不应传递到析构函数之外。此外,理解异常抛出、传递参数和虚函数调用之间的区别,以及如何通过引用捕获异常和合理使用异常规格也是关键。 对于效率提升,作者提出遵循80-20准则,提倡懒惰计算法,通过分期摊还计算来优化性能,讲解临时对象的创建和管理,以及如何通过重载和运算符的赋值形式优化代码。此外,书中还讨论了虚拟函数、多继承、虚基类和运行时类型信息(RTTI)等高级特性可能带来的成本。 最后,本书还涵盖了编程中的常见技巧,即idioms或patterns,这些技巧是提高C++代码质量、可读性和执行效率的有效手段。通过阅读这本书,读者不仅可以掌握C++语言的高级特性和最佳实践,还能学习如何在实际项目中应用这些知识,提升自己的编程技能和代码素质。"
资源详情
资源推荐
![](https://csdnimg.cn/release/download_crawler_static/10327363/bg10.jpg)
delete [] array;
}
BalancedBST *balTreeArray = // 建立一个 BalancedBST 对象数组
new BalancedBST[50];
...
deleteArray(cout, balTreeArray); // 记录这个删除操作
这里面也掩藏着你看不到的指针算法。当一个数组被删除时,每一个数组元素的析构函
数也会被调用。当编译器遇到这样的代码:
delete [] array;
它肯定象这样生成代码:
// 以与构造顺序相反的顺序来
// 解构 array 数组里的对象
for ( int i = 数组元素的个数 1; i >= 0;--i)
{
array[i].BST::~BST(); // 调用 array[i]的
} // 析构函数
因为你所编写的循环语句根本不能正确运行,所以当编译成可执行代码后,也不可能正
常运行。语言规范中说通过一个基类指针来删除一个含有派生类对象的数组,结果将是不确
定的。这实际意味着执行这样的代码肯定不会有什么好结果。多态和指针算法不能混合在一
起来用,所以数组与多态也不能用在一起。
值得注意的是如果你不从一个具体类(concrete classes)(例如 BST)派生出另一个
具体类(例如 BalancedBST),那么你就不太可能犯这种使用多态性数组的错误。正如条款
M33 所解释的,不从具体类派生出具体类有很多好处。我希望你阅读一下条款 M33 的内容。
(WQ 加注:VC++中,能够有正确的结果,因为它根本没有数组 new/delete 函数。)
3.4 Item M4:避免无用的缺省构造函数
缺省构造函数(指没有参数的构造函数)在 C++语言中是一种让你无中生有的方法。构
造函数能初始化对象,而缺省构造函数则可以不利用任何在建立对象时的外部数据就能初始
化对象。有时这样的方法是不错的。例如一些行为特性与数字相仿的对象被初始化为空值或
不确定的值也是合理的,还有比如链表、哈希表、图等等数据结构也可以被初始化为空容器。
但不是所有的对象都属于上述类型,对于很多对象来说,不利用外部数据进行完全的初
始化是不合理的。比如一个没有输入姓名的地址簿对象,就没有任何意义。在一些公司里,
所有的设备都必须标有一个公司 ID 号码,所以在建立对象以模型化一个设备时,不提供一
个合适的 ID 号码,所建立的对象就根本没有意义。
![](https://csdnimg.cn/release/download_crawler_static/10327363/bg11.jpg)
在一个完美的世界里,无需任何数据即可建立对象的类可以包含缺省构造函数,而需要
数据来建立对象的类则不能包含缺省构造函数。唉!可是我们的现实世界不是完美的,所以
我们必须考虑更多的因素。特别是如果一个类没有缺省构造函数,就会存在一些使用上的限
制。
请考虑一下有这样一个类,它表示公司的设备,这个类包含一个公司的 ID 代码,这个
ID 代码被强制做为构造函数的参数:
class EquipmentPiece {
public:
EquipmentPiece(int IDNumber);
...
};
因为 EquipmentPiece 类没有一个缺省构造函数,所以在三种情况下使用它,就会遇到
问题。第一中情况是建立数组时。一般来说,没有一种办法能在建立对象数组时给构造函数
传递参数。所以在通常情况下,不可能建立 EquipmentPiece 对象数组:
EquipmentPiece bestPieces[10]; // 错误!没有正确调用
// EquipmentPiece 构造函数
EquipmentPiece *bestPieces =
new EquipmentPiece[10]; // 错误!与上面的问题一样
不过还是有三种方法能回避开这个限制。对于使用非堆数组(non-heap arrays)(即不在堆
中给数组分配内存。译者注)的一种解决方法是在数组定义时提供必要的参数:
int ID1, ID2, ID3, ..., ID10; // 存储设备 ID 号的
// 变量
...
EquipmentPiece bestPieces[] = { // 正确, 提供了构造
EquipmentPiece(ID1), // 函数的参数
EquipmentPiece(ID2),
EquipmentPiece(ID3),
...,
EquipmentPiece(ID10)
};
不过很遗憾,这种方法不能用在堆数组(heap arrays)的定义上。
一个更通用的解决方法是利用指针数组来代替一个对象数组:
typedef EquipmentPiece* PEP; // PEP 指针指向
//一个 EquipmentPiece 对象
![](https://csdnimg.cn/release/download_crawler_static/10327363/bg12.jpg)
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 方法(参
见条款 M8)在内存中构造 EquipmentPiece 对象:
// 为大小为 10 的数组 分配足够的内存
// EquipmentPiece 对象; 详细情况请参见条款 M8
// 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<EquipmentPiece*>(rawMemory);
// construct the EquipmentPiece objects in the memory
// 使用"placement new" (参见条款 M8)
for (int i = 0; i < 10; ++i)
new (&bestPieces[i]) EquipmentPiece( ID Number );
注意你仍旧得为每一个 EquipmentPiece 对象提供构造函数参数。这个技术(和指针数
组的主意一样)允许你在没有缺省构造函数的情况下建立一个对象数组。它没有绕过对构造
函数参数的需求,实际上也做不到。如果能做到的话,就不能保证对象被正确初始化。
使用 placement new 的缺点除了是大多数程序员对它不熟悉外(能使用它就更难了),
还有就是当你不想让它继续存在使用时,必须手动调用数组对象的析构函数,然后调用操作
符 delete[]来释放 raw memory(请再参见条款 M8):(WQ 加注,已经有 placement
delete/delete []操作符了,它会自动调用析构函数。)
// 以与构造 bestPieces 对象相反的顺序
// 解构它。
for (int i = 9; i >= 0; --i)
![](https://csdnimg.cn/release/download_crawler_static/10327363/bg13.jpg)
bestPieces[i].~EquipmentPiece();
// deallocate the raw memory
operator delete[](rawMemory);
如果你忘记了这个要求而使用了普通的数组删除方法,那么你程序的运行将是不可预测
的。这是因为:直接删除一个不是用 new 操作符来分配的内存指针,其结果没有被定义。
delete [] bestPieces; // 没有定义! bestPieces
//不是用 new 操作符分配的。
有关 new、placement new 和它们如何与构造函数、析构函数一起使用的更多信息,请
见条款 M8。
对于类里没有定义缺省构造函数所造成的第二个问题是它们无法在许多基于模板
(template-based)的容器类里使用。因为实例化一个模板时,模板的类型参数应该提供一
个缺省构造函数,这是一个常见的要求。这个要求总是来自于模板内部,被建立的模板参数
类型数组里。例如一个数组模板类:
template<class T>
class Array {
public:
Array(int size);
...
private:
T *data;
};
template<class T>
Array<T>::Array(int size)
{
data = new T[size]; // 为每个数组元素
... //依次调用 T::T()
}
在多数情况下,通过仔细设计模板可以杜绝对缺省构造函数的需求。例如标准的 vector
模板(生成一个类似于可扩展数组的类)对它的类型参数没有必须有缺省构造函数的要求。
不幸的是,很多模板类没有以仔细的态度去设计。这样,没有缺省构造函数的类就不能与许
多模板兼容。当 C++程序员深入领会了模板设计以后,这样的问题应该不再那么突出了。这
会花多长时间,完全在于个人的造化。
最后讲一下在设计虚基类时所面临的要提供缺省构造函数还是不提供缺省构造函数的
两难决策。不提供缺省构造函数的虚基类,很难与其进行合作。因为几乎所有的派生类在实
![](https://csdnimg.cn/release/download_crawler_static/10327363/bg14.jpg)
例化时都必须给虚基类构造函数提供参数。这就要求所有由没有缺省构造函数的虚基类继承
下来的派生类(无论有多远)都必须知道并理解提供给虚基类构造函数的参数的含义。派生类
的作者是不会企盼和喜欢这种规定的。
因为这些强加于没有缺省构造函数的类上的种种限制,一些人认为所有的类都应该有缺
省构造函数,即使缺省构造函数没有足够的数据来完整初始化一个对象。比如这个原则的拥
护者会这样修改 EquipmentPiece 类:
class EquipmentPiece {
public:
EquipmentPiece( int IDNumber = UNSPECIFIED);
...
private:
static const int UNSPECIFIED; // 其值代表 ID 值不确定。
};
这允许这样建立 EquipmentPiece 对象
EquipmentPiece e; //这样合法
这样的修改使得其他成员函数变得复杂,因为不再能确保 EquipmentPiece 对象进行了
有意义的初始化。假设它建立一个因没有 ID 而没有意义的 EquipmentPiece 对象,那么大多
数成员函数必须检测 ID 是否存在。如果不存在 ID,它们将必须指出怎么犯的错误。不过通
常不明确应该怎么去做,很多代码的实现什么也没有提供:只是抛出一个异常或调用一个函
数终止程序。当这种情形发生时,很难说提供缺省构造函数而放弃了一种保证机制的做法是
否能提高软件的总体质量。
提供无意义的缺省构造函数也会影响类的工作效率。如果成员函数必须测试所有的部分
是否都被正确地初始化,那么这些函数的调用者就得为此付出更多的时间。而且还得付出更
多的代码,因为这使得可执行文件或库变得更大。它们也得在测试失败的地方放置代码来处
理错误。如果一个类的构造函数能够确保所有的部分被正确初始化,所有这些弊病都能够避
免。缺省构造函数一般不会提供这种保证,所以在它们可能使类变得没有意义时,尽量去避
免使用它们。使用这种(没有缺省构造函数的)类的确有一些限制,但是当你使用它时,它
也给你提供了一种保证:你能相信这个类被正确地建立和高效地实现。
4. 运算符
运算符重载--你不得不喜欢它们!它们允许给予你的自定义类型有着和 C++内建类
型完全相样的语法,更有甚者,它们允许你将强大的能量注入到运算符背后的函数体中,而
这是在内建类型上从未听说过的。当然,你能够使得如同“+”和“==”这样的符号做任何
你想做的事,这个事实意味着使用运算符重载你可能写出的程序完全无法理解。C++的老
剩余263页未读,继续阅读
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://profile-avatar.csdnimg.cn/bc0a9e1f69ad413f95cc4b7a23f475c3_baidu_41666198.jpg!1)
Lu_kuan@
- 粉丝: 200
- 资源: 6
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助
![](https://csdnimg.cn/release/wenkucmsfe/public/img/voice.245cc511.png)
最新资源
- 多模态联合稀疏表示在视频目标跟踪中的应用
- Kubernetes资源管控与Gardener开源软件实践解析
- MPI集群监控与负载平衡策略
- 自动化PHP安全漏洞检测:静态代码分析与数据流方法
- 青苔数据CEO程永:技术生态与阿里云开放创新
- 制造业转型: HyperX引领企业上云策略
- 赵维五分享:航空工业电子采购上云实战与运维策略
- 单片机控制的LED点阵显示屏设计及其实现
- 驻云科技李俊涛:AI驱动的云上服务新趋势与挑战
- 6LoWPAN物联网边界路由器:设计与实现
- 猩便利工程师仲小玉:Terraform云资源管理最佳实践与团队协作
- 类差分度改进的互信息特征选择提升文本分类性能
- VERITAS与阿里云合作的混合云转型与数据保护方案
- 云制造中的生产线仿真模型设计与虚拟化研究
- 汪洋在PostgresChina2018分享:高可用 PostgreSQL 工具与架构设计
- 2018 PostgresChina大会:阿里云时空引擎Ganos在PostgreSQL中的创新应用与多模型存储
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035111.png)
安全验证
文档复制为VIP权益,开通VIP直接复制
![](https://csdnimg.cn/release/wenkucmsfe/public/img/green-success.6a4acb44.png)