您的位置:首页 > 编程语言 > C语言/C++

C++析构函数的使用--异常安全

2009-05-13 18:59 295 查看
第一个例子:

void f()

{

FILE* __f;

__f=fopen(“filename”,”r+”);

if ( __f)

{

// file use ①

fclose(__f); //② 关闭文件

}

}

如果在//①file use过程中出现了错误,抛出了异常,程序就会异常回退,不会执行到②,文件也就没有关闭。解决这类问题可以使用异常处理:

void f()

{

FILE* __f;

__f=fopen(“filename”,”r+”);

if(__f)

{

try

{

// file use ①

}

catch(...)

{

fclose(__f); //② 关闭文件

throw; // 重新抛出异常

}

fclose(__f);//② 关闭文件

}

}

这种方案的缺点:

1.影响性能

2.背离异常设计的原则,异常处理代码和正常的代码没有很好的分离。只不过是:

if(error)

{

//错误处理

}

的偷懒写法。

在delphi 、java、 C#中引入了finally关键字,使这种设计方案更为流行;C#中的using只不过简化了try finally的写法。

更为合理的方案:

class file

{

FILE* __f;

Public:

file(char*filename,char* mode)

{

__f=fopen(filename,mode);

if (!__f) throw exception("open error");// 文件打开失败,抛出异常,表示类构造失败,这样在异常回退中就不会调用析构函数

}

~file()

{

fclose(__f); // 析构函数,关闭文件

}

operator FILE* ()

{

return __f;

}

};

void f()

{

file f1(“filename”,”r+”); //如果这边抛出异常,表示f1没有构造成功,就不会调用f1的析构

//①use file

};

如果f1构造成功,不管//①use file会不会出错,f1离开它的做用域时都将调用它的析构函数。

当然真正编码中,应该使用标准库中的ifstream和ofstream类。

第二个例子:

class A{

char* s;

int length;

public:

A(int n):length(n){

s=new char
;

}

A(const A&);

A& operator=(const A& a){ //①

if(this!=&a){

delete[] s;

length=a.length;

s=new char[length]; //②

//...

}

}

~A(){

delete[] s;

}

};

在①赋值运算符重载中,如果②抛出异常(bad_alloc),已经delete[] s
,但是析构函数还会再一次delete[]s
。这当然不是我们想要的。重新设计①:

A& operator=(constA& a){

if(this!=&a){

char* p;

p=new char[length];

//...

length=a.length;

delete[] s;
// delete 操作是不会抛异常的

s=p;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: