曾有人问了我个问题:如果在构造函数中抛出异常会怎么样?
现在可以回答了。
构造函数中抛出异常的主要问题是:当有多个资源分配时,如果出现异常,如何释放已经成功分配的资源。
下面是TCPL中推荐的一种方法:基本思想是将资源封装在对象中,然后将该对象以成员变量的形式聚合入你的类中。这个封装类在其析构函数中释放资源。这样,当你的类的构造函数中出现异常后,编译器会调用封装类的对象的析构函数,释放资源。
#include <iostream>
using namespace std;
template <class T>
void* ch_malloc(bool succ, char* name) {
cout << name << ":" << endl;
if (succ)
return malloc(sizeof(T));
else {
throw(exception("Memory Allocation Failed!"));
}
return 0;
}
class ch_File {
private:
void* data;
public:
ch_File(void* p) { data = p; }
~ch_File() {
cout << "=>ch_File::~ch_File()" << endl;
cout << " data:" << data << endl;
delete data; //释放资源
}
};
class Klass {
private:
ch_File p1;
void* p2, *p3;
public:
Klass()
: p1(ch_malloc<char>(true, "p1")),
p2(ch_malloc<char>(false, "p2")), // <-- 调用p1的析构函数
p3(ch_malloc<char>(true, "p3")) {
// will not reach here
cout << "=>Klass::Klass" << endl;
}
};
int main(int argc, char* argv[]) {
try {
Klass k;
} catch (exception e) {
cout << e.what() << endl;
}
return 0;
}
输出
p1:
p2:
=>ch_File::~ch_File()
data:00386580
Memory Allocation Failed!
第二种方法:
在构造函数中使用 function-try-block,如下代码所示。
这种方法比较简洁,不用将所有资源封装,也不一定要用auto_ptr。
但是并不是所有的编译器都支持 function-try-block,比如vc6。vc9和g++都支持。vc7,vc8没有验证。
#include <iostream>
using namespace std;
template <class T>
void* ch_malloc(bool succ, char* name) {
cout << "allocating " << name << endl;
if (succ)
return malloc(sizeof(T));
else {
throw(exception("Memory Allocation Failed!"));
}
return 0;
}
class Klass {
private:
void* p1, *p2, *p3;
public:
Klass() try : p1(0), p2(0), p3(0) {
p1 = ch_malloc<char>(true, "p1");
p2 = ch_malloc<char>(false, "p2");
p3 = ch_malloc<char>(true, "p3");
} catch (...) {
cout << "=>ctor-try-block";
delete this; // compiler will insert a "throw" here
}
~Klass() {
cout << "=>Klass::~Klass()" << endl;
cout << " p1:" << p1 << endl;
cout << " p2:" << p2 << endl;
cout << " p3:" << p3 << endl;
delete p1;
delete p2;
delete p3;
}
};
int main(int argc, char* argv[]) {
try {
Klass k;
} catch (exception e) {
cout << e.what() << endl;
}
return 0;
}
输出
allocating p1
allocating p2
=>ctor-try-block=>Klass::~Klass()
p1:00375FC8
p2:00000000
p3:00000000
Memory Allocation Failed!