干净退出 - 建议? [英] clean exit - suggestions?

查看:63
本文介绍了干净退出 - 建议?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,


我的功能如下:


void fnc(){

char * mem1,* mem2,* mem3,* mem4;

//很多代码......

// mem1,2,3,4分配了

//大量的代码和条件检查

if(condition_failed)

{

// blah blah

//免费mem1,mem2,mem3,mem4

返回;

}


if(condition2_failed)

{

// blah blah

//免费mem1,mem2,...

返回;

}


//这里的例程结束(干净的退出代码):

//免费mem1,mem2,mem3,mem4

}


通常,我会使用编译器特定的解决方案,将大部分代码

放在__try()和干净的退出中_finally()块中的代码然后到达

干净的退出代码我会调用__leave。


或者使用标签然后转到clean_exit


除了goto或compil之外,还有更好的方法特定解决方案?


-

Elias

解决方案

lallous写道:


您好,

我的功能如下:

void fnc(){
char * mem1, * mem2,* mem3,* mem4;
//很多代码......
// mem1,2,3,4已分配
//大量代码和条件检查
if(condition_failed)
// blah blah
//免费mem1,mem2,mem3,mem4
返回;
}

if(condition2_failed)
//
//免费mem1,mem2,...
返回;
}

//这里的例程结束(干净的退出代码):
//免费mem1,mem2,mem3,mem4


通常,我会使用编译器特定的解决方案通过将__try()中的大部分代码和_finally()块中的干净退出代码放入,然后到达
干净的退出代码,我将调用__leave。

或使用标签然后转到clean_exit

除了goto或编译器特定的解决方案之外还有更好的方法吗?




使用std :: string而不是动态分配的字符数组。


#include< string>


void fnc()

{

std :: string mem1;

std :: string mem2;


mem1 =" Hallo";

mem2 =" World";


//看马!我不需要做任何事情。 mem1和mem2

//将自己分配的内存全部释放

}


-

Karl Heinz Buchegger
kb******@gascad.at


" Karl Heinz Buchegger" < KB ****** @ gascad.at>在消息中写道

新闻:3F *************** @ gascad.at ...

lallous写道:


您好,

我的功能如下:

void fnc(){
char * mem1,* mem2,* mem3,* mem4;
//很多代码......
// mem1,2,3,4已分配
//大量代码和条件检查
如果( condition_failed)
// blah blah
//免费mem1,mem2,mem3,mem4
返回;
}
如果( condition2_failed)
// blah blah
//免费mem1,mem2,...
返回;
}
// //例程结束(干净退出代码):
//免费mem1,mem2,mem3,mem4


通常,我会使用编译器特定的解决方案__try()中的
代码和_finally()块中的干净退出代码然后到达
干净的退出代码我将调用__leave。

或使用标签然后转到clean_exit

任何更好的方式,其他比goto或编译器特定的解决方案?



使用std :: string而不是动态分配的字符数组。

#include< string>

void fnc()
{
std :: string mem1;
std :: string mem2;

mem1 =" Hallo";
mem2 =" World";

//看看Ma!我不需要做任何事情。 mem1和mem2
//将自己释放分配的内存
}

- Karl Heinz Buchegger
kb ****** @ gascad.at




您好,


您的解决方案是一个提示......但我使用这样的缓冲区来执行文件i / o和

无法真正使用std :: string ....


有时我的代码如下:

fclose(fp1); FCLOSE(FP2);自由(MEM1); myObj-> DEINIT();等等...

所以你看到清理代码并不总是通过使用对象来解决...所以

我的问题是如何避免重复清理代码在

的情况下,我想在功能中间返回。


-

Elias


" lallous" < LA ***** @ lgwm.org>在消息中写道

news:bt ************ @ ID-161723.news.uni-berlin.de ...

I有这样的功能:

void fnc(){
char * mem1,* mem2,* mem3,* mem4;
//很多代码......
// mem1,2,3,4已分配
//大量代码和条件检查
if(condition_failed)
{
// blah blah
/ / free mem1,mem2,mem3,mem4
返回;
}
如果(condition2_failed)
{
// blah blah
/ / free mem1,mem2,...
返回;
}
//这里的例程结束(干净的退出代码):
//免费mem1, mem2,mem3,mem4


通常,我会使用编译器特定的解决方案,将大部分
代码放在__try()中,将干净的退出代码放在_finally()块中然后到达
干净的退出代码我会调用__leave。
或者使用标签然后转到clean_exit

除了goto或编译器特定的解决方案之外还有更好的方法吗?


您发布的代码问题是代码重复(=维护

头疼,这无疑会导致以后的错误)并且它不是

异常安全。


如果它只是释放困扰你的char *,为什么不使用

std :: string类?


#include< string>

void fnc()

{

std :: string mem1,mem2 ,mem3,mem4;


//很多代码...

//大量的代码和条件检查

if (condition_failed)

{

// blah blah

//无需显式释放mem1,mem2,mem3,mem4!

返回;

}


if(condition2_failed)

{

/ / blah blah

//无需明确释放mem1,mem2,mem3,mem4!

返回;

}


//无需明确释放mem1,mem2,mem3,mem4!

}


这样做的好处不仅仅是所有的记忆字符串使用的ory是自动释放的,无论函数如何退出(返回或

异常),而且使用std :: string的字符串操作也很多

更容易编码和理解。类似于std :: vector类是动态创建数组的优秀替代品。也可以使用这个类

,无需担心显式内存管理。


对于函数退出时需要完成的其他任务,请考虑使用

RAII习语

http://c2.com/cgi/wiki?ResourceAcqui...nitialization)

RAII的一个例子是std :: auto_ptr类。 RAII习惯用法的基本思想是

创建一个本地对象,它有一个析构函数,可以在函数退出时执行操作

(析构函数实际上取代了

非标准_finally子句)。由于本地对象的析构函数总是在函数存在时被调用,因此析构函数可以在非标准的_finally()子句中执行你现在所做的事情。


#include< iostream>

class AutoCleanup

{

public:

AutoCleanup();

~AutoCleanup()

{

std :: cout<< AutoCleanup dtor << std :: endl

}

}


void fnc()

{

AutoCleanup tmp;

//大量代码和条件检查

if(condition_failed)

{

//返回语句导致

// AutoCleanup :: ~AutoCleanup被调用

返回;

}


if(condition2_failed)

{

//返回语句导致

// AutoCleanup :: ~AutoCleanup被称为

返回;

}


//当函数完成时

// AutoCleanup :: ~AutoCleanup将被调用

}


此外,当抛出异常时,AutoCleanup :: ~AutoCleanup将是

叫。 RAII成语是一种非常方便的技术,其有用性不仅限于释放内存或其他资源。例如对于UI代码

,您可以创建一个类,将鼠标光标更改为沙漏上的
构造,并在销毁时恢复上一个鼠标光标:
< br $>
class HourGlassCursor

{

public:

HourGlassCursor():prev_(getCursor())

{

setCursor(crHourGlass);

}


~ HourGlassCursor()

{

setCursor(prev_);

};


private:

光标prev_;

};


无效计算()

{

HourGlassCursor hgc;

//做一些冗长的处理...

}


即使抛出异常,光标也会一直被恢复。 />
-

Peter van Merkerk

peter.van.merkerk(at)dse.nl




Hello,

I have a function like:

void fnc() {
char *mem1, *mem2, *mem3, *mem4;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_failed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}

Usually, I would use compiler specific solution by putting most of the code
in __try() and the clean exit code in _finally() block then to reach the
clean exit code I would invoke __leave.

Or use lables and then goto clean_exit

Any better way, other than goto or compiler specific solution?

--
Elias

解决方案

lallous wrote:


Hello,

I have a function like:

void fnc() {
char *mem1, *mem2, *mem3, *mem4;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_failed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}

Usually, I would use compiler specific solution by putting most of the code
in __try() and the clean exit code in _finally() block then to reach the
clean exit code I would invoke __leave.

Or use lables and then goto clean_exit

Any better way, other than goto or compiler specific solution?



use a std::string instead of dynamically allocated character arrays.

#include <string>

void fnc()
{
std::string mem1;
std::string mem2;

mem1 = "Hallo";
mem2 = "World";

// look Ma! I don''t have to do anything. mem1 and mem2
// will free the allocated memory all by themselfs
}

--
Karl Heinz Buchegger
kb******@gascad.at


"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:3F***************@gascad.at...

lallous wrote:


Hello,

I have a function like:

void fnc() {
char *mem1, *mem2, *mem3, *mem4;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_failed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}

Usually, I would use compiler specific solution by putting most of the code in __try() and the clean exit code in _finally() block then to reach the
clean exit code I would invoke __leave.

Or use lables and then goto clean_exit

Any better way, other than goto or compiler specific solution?



use a std::string instead of dynamically allocated character arrays.

#include <string>

void fnc()
{
std::string mem1;
std::string mem2;

mem1 = "Hallo";
mem2 = "World";

// look Ma! I don''t have to do anything. mem1 and mem2
// will free the allocated memory all by themselfs
}

--
Karl Heinz Buchegger
kb******@gascad.at



Hello,

Your solution is a hint...but I am using such buffers to do file i/o and
cannot really use std::string....

And sometimes I have code like:
fclose(fp1); fclose(fp2); free(mem1); myObj->DeInit(); blah blah...
So you see how the cleanup code is not always solved by using objects...so
my question was how to avoid repeating the cleanup code over and over in
case I want to return in the middle of the function.

--
Elias


"lallous" <la*****@lgwm.org> wrote in message
news:bt************@ID-161723.news.uni-berlin.de...

I have a function like:

void fnc() {
char *mem1, *mem2, *mem3, *mem4;
// lots of code...
// mem1, 2, 3, 4 got allocated
// lots of code and condition checks
if (condition_failed)
{
// blah blah
// free mem1, mem2, mem3, mem4
return;
}

if (condition2_failed)
{
// blah blah
// free mem1, mem2, ...
return;
}

// here the end of routine (clean exit code):
// free mem1, mem2, mem3, mem4
}

Usually, I would use compiler specific solution by putting most of the code in __try() and the clean exit code in _finally() block then to reach the
clean exit code I would invoke __leave.
Or use lables and then goto clean_exit

Any better way, other than goto or compiler specific solution?



The problem with code you posted is code duplication (= maintenance
headache, which will no doubt lead to bugs later) and that it is not
exception safe.

If it is just freeing char* that is bothering you, why not use the
std::string class?

#include <string>
void fnc()
{
std::string mem1, mem2, mem3, mem4;

// lots of code...
// lots of code and condition checks
if (condition_failed)
{
// blah blah
// No need to explicitly free mem1, mem2, mem3, mem4!
return;
}

if (condition2_failed)
{
// blah blah
// No need to explicitly free mem1, mem2, mem3, mem4!
return;
}

// No need to explicitly free mem1, mem2, mem3, mem4!
}

The advantage of this is not only that all memory used by the string is
automatically released, no matter how the function exits (return or
exception), but also that string manipulation with the std::string is much
easier to code and understand. Similary the std::vector class is an
excellent replacement for dynamically created arrays; also with this class
there is no need to worry about explicit memory management.

For other tasks that need to be done when a functions exits, consider using
the RAII idiom
(http://c2.com/cgi/wiki?ResourceAcqui...nitialization). An example of
RAII is the std::auto_ptr class. The basic idea of the RAII idiom is to
create a local object which has a destructor that perfoms the operations
necessary when the function is exited (the destructor essentially replaces
the non-standard _finally clause). Since the destructor of local objects is
always called when the function exists, the destructor can perfom the
things you now do in the non-standard _finally() clause.

#include <iostream>
class AutoCleanup
{
public:
AutoCleanup();
~AutoCleanup()
{
std::cout << "AutoCleanup dtor" << std::endl
}
}

void fnc()
{
AutoCleanup tmp;
// lots of code and condition checks
if (condition_failed)
{
// The return statement causes
// AutoCleanup::~AutoCleanup to be called
return;
}

if (condition2_failed)
{
// The return statement causes
// AutoCleanup::~AutoCleanup to be called
return;
}

// When the function finishes
// AutoCleanup::~AutoCleanup will be called
}

Also when a exception is thrown the AutoCleanup::~AutoCleanup will be
called. The RAII idiom is a very handy technique which usefullness is not
restricted to releasing memory or other resources. For example for UI code
you could make a class the changes the mouse cursor to a hourglass on
construction and restores the previous mouse cursor on destruction:

class HourGlassCursor
{
public:
HourGlassCursor() : prev_(getCursor())
{
setCursor(crHourGlass);
}

~HourGlassCursor()
{
setCursor(prev_);
};

private:
Cursor prev_;
};

void calculate()
{
HourGlassCursor hgc;
// do some lengthy processing...
}

The cursor will always be restored, even if an exception is thrown.
--
Peter van Merkerk
peter.van.merkerk(at)dse.nl





这篇关于干净退出 - 建议?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆