C++ 异常使用总结
一、注意在构造函数中的异常
如构造函数中抛出异常的,C++的异常机制是不会去调用它的析构函数的。这个问题会造成一些内存泄露的问题。
看一下这个例子:
class CSpace
{
public:
CSpace()
{
m_pSpace = newint[100];
//
throw 1;
}
~CSpace()
{
deletem_pSpace;
}
private:
int *m_pSpace;
//...
public:
//...
};
void Render()
{
try
{
CSpace space;
//....
}
catch(CException* e)
{
}
}
这里CSpace的构造函数在位m_pSpace申请完空间后,抛出异常,那么在Render函数进行异常处理。这个时候因为系统认为CSpace对象还没构造好,就不去调用它的析构函数。所以麻烦来了,谁去处理m_pSpace呢?这个成为了有一个被遗弃的指针,永远不会被释放。
还好这个问题完全可以从设计上去解决。
我们可以使用Init和Release之类的函数。还是直接看代码。
class CSpace
{
public:
CSpace()
{
m_pSpace = NULL;
}
~CSpace()
{
}
private:
int *m_pSpace;
//...
public:
void Init()
{
m_pSpace = newint[100];
}
voidRelease()
{
deletem_pSpace;
m_pSpace = NULL;
}
//...
};
原本来说构造函数就只是负责一些变量的赋初值工作
二、捕获异常的类型
抛出捕获的异常,应该用什么类型比较好。看了一些资料,还是感觉引用是最不错的。
这里应该也就三种情况:
1. catch(Exceptionex) ,这个主要是每次catch都要拷贝一次,这个提高了catch的代价;
2. catch(Exception* ex),这个最大缺陷,也是指针的通病,你要怎么去处理这个异常指针,要不要delete这个指针;
主要是要试想一下,如果这个异常对象是存在于堆里的话,你在这里delete掉,肯能导致其它地方再次使用时,会带来很大的麻烦。
3. catch(Exception& ex),这个既解决了拷贝的代价,也不必再去考虑释放异常对象。
上面三种情况,就知道使用引用处理异常的捕获是最好的选择。
三、MFC中的CException
这个是比较麻烦,因为这里catch的类型都是指针型的,需要你自己去调用CException中的Delete函数来进行释放。
当然用TRY CATCH宏的话,就不用手动去调用Delete函数了。
四、VisualStudio中的编译选项
在Vs中如果选择/EHa编译选项的话,可以用catch捕获到一些不是throw的异常,甚至连Access violations也能捕获到。可以看官网中的介绍。
会持续更新,如果有了新发现……