1

我正在尝试以可读的方式构建我的代码。我读过一种方法如下:

if(Init1() == TRUE)
{
    if(Init2() == TRUE)
    {
        if(Init3() == TRUE)
        {
            ...
            Free3();
        }
        Free2();
    }
    Free1();
}

我喜欢这种做事方式,因为它使每个都保持FreeX在它的匹配InitX循环中,但是如果嵌套超过三个级别,它很快就会变得不可读并且超过 80 列。许多函数可以分解为多个函数,这样就不会发生这种情况,但是为了避免过多的嵌套而分解一个函数似乎很愚蠢。特别是,考虑一个对整个类进行初始化的函数,该初始化需要十个或更多的函数调用。那是十个或更多级别的嵌套。

我确定我想太多了,但是上面是否缺少一些基本的东西?可以以可读的方式进行深度嵌套吗?或者以某种方式进行重组,同时保持每个循环都FreeX在自己的InitX循环中?

顺便说一句,我意识到上面的代码可以压缩为if(Init1() && Init2()...,但代码只是一个示例。每次调用之间会有其他代码InitX可以防止这种压缩。

4

5 回答 5

4

由于您包含了 C++ 标记,因此您应该使用 RAII - Resource Acquisition Is Initialization。有很多很好的在线资源解释了这个概念,它会让很多与资源管理有关的事情变得容易得多。

于 2013-09-30T11:23:09.077 回答
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();

您将没有嵌套的 if,您的代码将清晰明了(并专注于积极的情况)。

您只需为资源 1、2 和 3 编写 RAII 包装器。

于 2013-09-30T11:27:18.053 回答
2

正如其他人所指出的,显而易见的答案是 RAII。但是,如果在没有 RAII 的情况下出现嵌套过深的问题,您真的应该问问自己是否没有让您的函数过于复杂。一个函数应该很少有超过十行(包括这样的检查)。如果您查看真实案例,您会发现将函数分解几乎总是更有意义。即使使用 RAII,通常每个函数也应该只有一个 RAII 类的实例。(当然也有例外;可以说,类似的东西std::lock_guard不应该算在内。)

于 2013-09-30T11:52:16.500 回答
0

我建议使用 switch 语句。当涉及到这样的代码时,我非常喜欢 switch 语句

希望这可以帮助。

switch (i) {
    case 1:
        // action 1
        break;
    case 2:
        // action 2
        break;
    case 3:
        // action 3
        break;
    default:
        // action 4
        break;
}
于 2013-09-30T11:27:11.600 回答
-1

您可能听说过 goto 是邪恶的,但是如果您坚持使用 c,那么使用 goto 处理这样的异常并没有什么“脏”:

foo()
{
  if (!Init1())
    goto Error1;
  if (!Init2())
    goto Error2;
  ...
  ...
Error2:
  Free2();
Error1:
  Free1();
}
于 2013-09-30T11:33:13.970 回答