在程序的一般设计中,怎么判定一个方法适合按你预想的那样执行了,在C语言中,返回一个整数是常用的方法,比如一个-1,比如linux打开一个文件open,失败返回-1,大家如果都遵守还好,可是还是会出现返回0是失败的。Java中对于异常错误处理使用异常,异常是强制使用的,在C++中不是,你可以完全不使用,说实话我很好使用,有时基本都忘了,使用的最多的还是C的风格,这两个对于异常处理的风格没有孰优孰劣。C的风格简单,明了。C++的异常,可以包含更多的信息,方便日志,调试。
标准库中定义了异常类,可是那只框架层次的,在实际使用中,如果确定使用异常处理来进行异常错误处理,那么还需要在标准库之上拓展,或者自己再造轮子。
今天我不会讲在C++中使用异常的语法,只是讲一些注意点。
1.在构造函数中抛出异常
在构造函数中抛出异常,那说明什么,对象构造没成功,那么你精心设计的析构函数就可能没法调用,在构造函数中如果在抛出之前你什么的占用了一些资源,那必须你自己手动的释放。
比如这样:
A::A()
{
p = new int[10];
//上面的内存分配完成,然后你抛出一个异常
}
A::~A()
{
delete[] p;
}
2.不能让析构函数抛出异常,有问题内部解决
析构函数是资源管理的不可多得的还途径,不管什么情况,请保证它执行完。
在基层体系中,你可能回担心在子类的析构函数中抛出异常,那父类的析构函数还会调用吗?我们先来看看类构造的顺序,我们只谈构造时生成的,static关键字就不谈了。
下面代码示例:
#ifndef SUPER_HPP
#define SUPER_HPP
#include <iostream>
/**
* @brief The Super class 超类 父类
*/
class Super
{
public:
Super() {std::cout << "Super\n";}
virtual ~Super() {std::cout << "Super 析构\n";}
};
#endif // SUPER_HPP
#ifndef SUB_HPP
#define SUB_HPP
#include "super.hpp"
class A
{
public:
A() {std::cout << "A\n";}
virtual ~A(){std::cout << "A 析构\n";}
};
/**
* @brief The Sub class 子类
*/
class Sub : public Super
{
public:
Sub():Super() {std::cout << "Sub\n";}
virtual ~Sub(){throw 1;std::cout << "Sub 析构\n";}
protected:
private:
A a;
};
#endif // SUB_HPP
#include "sub.hpp"
int main()
{
Sub *s = new Sub();
try {
delete s;
}catch(int i) {
std::cout << i << std::endl;
}
}
如结果所示,父类先构造,然后是数据成员然后调用构造函数。C++会保证完全构造的对象是调用它的析构函数,所以前面的在有层次结构的类中的构造函数中抛出异常也是如此。不过抛出异常的析构函数不会调用完成,如上图少输出一句话,如果后续还有资源释放操作,那就会造成泄漏。