我正在尝试以可读的方式构建我的代码。我读过这样做的一种方法如下:
if(Init1() == TRUE)
{
if(Init2() == TRUE)
{
if(Init3() == TRUE)
{
...
Free3();
}
Free2();
}
Free1();
}
我喜欢这种做事方式,因为它将每个FreeX
保持在匹配的InitX
循环内,但如果嵌套超出三个级别,它很快就会变得不可读并超过80列。许多函数可以分解为多个函数,这样就不会发生这种情况,但为了避免过多的嵌套级别,分解函数似乎很愚蠢。特别是,考虑一个为整个类进行初始化的函数,其中初始化需要十个或更多函数调用。这是十层或更多层次的嵌套。
我确信我已经过度思考了这一点,但是上面有什么根本我缺失的东西吗?深度嵌套可以以可读的方式完成吗?或者以某种方式进行重组,同时将每个FreeX
保留在自己的InitX
循环中?
顺便说一句,我意识到上面的代码可以压缩到if(Init1() && Init2()...
,但代码只是一个例子。每个InitX
调用之间会有其他代码阻止这种压缩。
答案 0 :(得分:4)
由于您包含了C ++标记,因此您应该使用RAII - 资源获取是初始化。有很多很好的在线资源可以解释这个概念,它将使很多与资源管理相关的事情变得更加容易。
答案 1 :(得分:2)
我确信我已经过度思考了这一点,但是上面有什么根本我缺失的东西吗? [...]或者以某种方式进行重组,同时将每个FreeX保留在自己的InitX循环中?
是。这是一个代码的教科书案例,将从RAII代码中获益匪浅:
而不是构造:
if(init(3) == TRUE)
{
free3();
}
考虑一下:
raii_resource3 r3 = init3(); // throws exception if init3 fails
// free3 called internally
// by raii_resource3::~raii_resource3
您的完整代码变为:
raii_resource1 r1 = init1();
raii_resource2 r2 = init2();
raii_resource3 r3 = init3();
您将没有嵌套ifs,您的代码将清晰明了(并专注于积极的情况)。
您只需要为资源1,2和3编写RAII包装器。
答案 2 :(得分:2)
正如其他人所指出的,显而易见的答案是RAII。但如果
如果没有RAII,你就会出现过深的嵌套问题
应该问问自己,你是不是在做自己的职能
太复杂。函数应该很少超过约
十行(包括此类检查)。如果你看一下真实案例,
你会发现打破它几乎总是更有意义
功能。即使使用RAII,您通常也应该只有一个
每个函数的RAII类的实例。 (也有例外,
当然;可以说,std::lock_guard
之类的东西不应该
数。)
答案 3 :(得分:0)
我建议使用switch语句。 当谈到像这样的代码时,我非常喜欢switch语句。
希望这有帮助。
switch (i) {
case 1:
// action 1
break;
case 2:
// action 2
break;
case 3:
// action 3
break;
default:
// action 4
break;
}
答案 4 :(得分:-1)
你可能听说过这是邪恶的,但如果你坚持使用c,那么使用gotos来处理这样的异常并不是“肮脏”:
foo()
{
if (!Init1())
goto Error1;
if (!Init2())
goto Error2;
...
...
Error2:
Free2();
Error1:
Free1();
}