关于函数有一个try-catch的东西,我认为有时可能非常有用:
bool function()
try
{
//do something
}
catch(exception_type & t)
{
//do something
}
所以问题的第一部分:这种风格在一般情况下是否被视为不好?
我使用这种方法的具体例子是:
我们在c和c ++中有很多代码的项目。我们有自定义异常类型(不是std :: exception派生的)。我需要集成XML库并将所有异常强制转换为我们的类型。所以,基本上,最后一步是从XML库中捕获所有异常并转换它们。
之前的功能:
bool readEntity(...)
{
while(...)
{
if(...)
{
//lot's of code...
}
}
}
后:
bool readEntity(...)
try
{
while(...)
{
if(...)
{
//lot's of code...
}
}
}
catch(XMLBaseException & ex)
{
//create our exception and throw
}
我的想法是这样的:我明确表示我的意图是将从一种类型派生的所有异常转换为自定义类型并且我们保持屏幕没有水平滚动条(因为水平滚动条很糟糕)。
嗯,在代码审查过程中,我对这种方法的批评非常明确。
所以我想听听你的想法。
更新:只是要明确:重构函数不是一个选项。实际上写得很好。
答案 0 :(得分:12)
实际上,功能级try块的唯一原因是构造函数,否则它是一个有点模糊的功能,不会给你带来那么多。这样做很容易:
bool readEntity(...)
{
try
{
while(...)
{
if(...)
{
//lot's of code...
}
}
}
catch(XMLBaseException & ex)
{
//create our exception and throw
}
}
如果您遇到水平滚动问题,那么要做的就是拆分您的代码。 try / catches是复杂的,这应该在嵌套级别表示,而不是隐藏。
在构造函数中,这是一个不同的问题:没有其他方法可以捕获初始化列表中的异常:
SomeClass::SomeClass(parameter p1, parameter p2) : Member1(p1), Member2(p2)
try
{
}
catch(Exception &ex)
{
// handle and rethrow
}
当然,如果你在构建过程中遇到异常,除了log和rethrow之外你不可能做很多事情来恢复(在构造函数的情况下它会被重新抛出)。你的物体尚未完全构造,你无法用它做任何事情。唯一值得信赖的是参数(尽管如果初始化失败,那可能是由于参数错误)。
有关此问题的讨论,请参阅此GOTW。
答案 1 :(得分:4)
要明确的是:重新抛出和重新打包异常并不是一种糟糕的做法,因为它可以最大限度地减少外部依赖的暴露,所以这是一件好事。
但是,函数级try-catch用于构造函数初始化。在代码中保存几个水平空格不值得使用相对模糊的语言功能。如果你真的缩进那么远,最好重构嵌套代码!
答案 2 :(得分:1)
在Herb Sutters GotW site处对构造函数/函数try块的一般无用性进行了很好的讨论。
答案 3 :(得分:0)
该函数应该返回一个bool所以你可以返回一个true或false但是如果函数失败并且bool被用于除了成功标志以外的东西(这是不好的做法除非纯c)它应该扔到告诉来电者它不起作用。