来源
https://blog.csdn.net/qq_37375427/article/details/78797953
C++bug来源
- 野指针
- 对象构造未成功(在构造函数中出现了异常)
构造函数
- 只提供自动初始化成员变量的机会
- 不能保证初始化逻辑一定成功
- 执行return语句后构造函数立即结束
结论:
构造函数能决定的只是对象的初始状态,而不是对象的诞生!!!,会出现半成品对象
半成品对象
半成品对象的概念:
- 初始化操作不能按照预期完成二得到的对象
- 半成品对象是合法的C++对象,但是同时它也是Bug的重要来源
一般企业中最难以调试的Bug,一是野指针(后面文章会写),其次就是这个半成品对象带来的Bug。
利用二阶构造解决
那么我们该如何避免这样的Bug呢?下面就引出二阶构造的含义:
工程开发中的构造过程可分为:
- 不可能出现异常情况的操作
资源无关的初始化操作 - 需要使用系统资源的操作
可能出现异常情况,如:内存申请,访问文件
二阶构造大体流程:
代码示例
#include <iostream>
using namespace std;
class TwoPhaseCons
{
public:
static TwoPhaseCons* NewInstance();//对象构造函数:整合第一第二阶段构造函数
private:
TwoPhaseCons(){}//第一阶段构造函数
bool construct() { return true; }//第二阶段构造函数
};
int main()
{
TwoPhaseCons* obj = TwoPhaseCons::NewInstance();
cout << "obj=" << obj << endl;
delete obj;
return 0;
}
TwoPhaseCons * TwoPhaseCons::NewInstance()
{
TwoPhaseCons* ret = new TwoPhaseCons();
//分配内存失败或者第二阶段构造函数失败
if (!(ret && ret->construct()))
{
delete ret;
ret = nullptr;
}
return ret;
}
运行结果:
obj=012C7460
说明
第一阶段构造函数与第二阶段构造函数
放到private
里面了,外部无法调用。
但是在public中,定义的是static 型的NewInstance函数
,返回TwoPhaseCons类型的对象,那么通过它就可以调用private里面的构造函数
。例如在NewInstance函数里可以有如下代码: TwoPhaseCons* ret = new TwoPhaseCons();
,因为处于NewInstance内部,所以它可以调用构造函数。
同时我们也可以看出,用了二阶构造模式后,对象只能在堆空间上进行构造而不能在栈空间上构造
,这样好么?答案是肯定的,因为工程上的对象往往是巨大的,一般都会放到堆空间上进行构造。
总结
- 构造函数只能决定对象的初始化状态
- 构造函数中初始化操作的失败不影响对象的诞生
- 初始化不完全的半成品对象是Bug的主要来源
- 二阶构造人为的将初始化过程分成两部分
- 二阶构造能够确保创建的对象都是完整初始化的