2014-09-27 74 views
0

我遇到过这样一种情况:我有一堆需要按顺序初始化的“系统”,如果所有的前进系统都成功初始化,下一个系统只会被初始化。切换语句而不是多重嵌套if - else?

这使我得到了一整套嵌套的if - else语句。这里有一些可视化的伪代码。

bool mainInit() { 
    if (!system1Init()) { 
     reportError(); // some error reporting function 
    } 
    else { 
     if (!system2Init()) { 
      reportError(); 
     } 
     else { 
      if (!system3Init()) { 
      // ... and so on 

我发现当你得到几个关卡时,这看起来就像一团糟。

现在我想用一个switch语句来代替,开始在第一种情况下,通过下降到成功的其他情况下,只要有一个错误打破。

bool mainInit() { 

    switch (1) { 
    case 1: 
     if (!system1Init()) { 
      reportError(); 
      break; 
     } 
    case 2: 
     if (!system2Init()) 
      reportError(); 
      break; 
     } 
    // .... 
} 

现在,我更喜欢这个了。我发现读起来容易多了,特别是有一些体面的评论,但我对编程相当陌生。

所以,我的问题是:怎么看这不是开关语句是如何传统上使用(至少从我所看到),是这样的可以接受的,或将本被认为是不好的形式?

作为新的节目,我想不发展太多的坏习惯,可能阻挠,并为其他程序员在路上事情变得更加困难。

我做了搜索,但大部分我发现曾与替换如果链来完成 - else if语句,而不是取代嵌套的。依次

+0

后,所有的if语句中会发生什么? 'mainInit'返回什么? – Beta 2014-09-27 21:14:31

+0

如何在失败时返回“假”或“抛出......”? – 2014-09-27 21:16:48

+0

你不必做'else {if(){'大多数人做'else if(){'。 – Galik 2014-09-27 21:39:22

回答

3

参考所有的系统在一个阵列,例如一个std::vector<mySystem*>,和环就过去了,在折断第一故障。通过这种方式,即使对于500多个系统,您的整个代码也会减少到少于5行代码。

建议的交换机黑客是一个邪恶的例子XY problem solving:你真正的问题是你没有系统数组,并且正在使用命名变量,从而消除了所有选项以更灵活地使用所有系统,如在循环。

+0

我在我的问题的代码中犯了一个错误,我没有直接处理系统对象(我甚至不确定是否有它下面的所有对象)我正在初始化部分ac库以供使用。我道歉。我想我真的不明白我应该问什么。那么我会使用一个函数向量吗? – liquidhand 2014-09-27 21:55:25

+0

我不认为这个问题是一个XY问题,因为用户首先提出正确的问题,并给出了他可以做什么的可能答案。 XY是当用户只问“我应该做一个开关”而没有先说明真正的问题。 – 2014-09-27 22:06:20

0

假设所有system#Init()调用在编译时已知的,你可以很容易的把它们放在一个表,然后遍历该表。

typedef (*system_init)(void); 

system_init initialization_functions[] = 
{ 
    system1Init, 
    system2Init, 
    system3Init, 
     ... 
    systemNInit 
}; 

bool mainInit() 
{ 
    for(size_t idx(0); idx < sizeof(initialization_functions)/sizeof(initialization_functions[0]); ++idx) 
    { 
     if(!initialization_functions[idx]()) 
     { 
      ReportError(); 
      return false; 
     } 
    } 
    return true; 
} 

然而,现有的代码看起来不正确,因为第一mainInit()只要求system1Init(),然后退出。可能不是你想要的东西。

if(!system1Init()) 
{ 
    ReportError(); 
    return false; 
} 
// if you add an else, the system2Init() does not get called 
// even if system1Init() succeeds 
if(!system2Init()) 
{ 
    ReportError(); 
    return false; 
} 
[...] 
return true; 

切换器会回答您的问题吗?不像它写的那样。也就是说,如果你想用计数器调用mainInit()函数,它可能很有用。 Drupal使用这一机制:

bool mainInit(int idx) 
{ 
    bool r(true); 
    switch(idx) 
    { 
    case 1: 
     r = system1Init(); 
     break; 

    case 2: 
     r = system2Init(); 
     break; 

    [...] 
    } 
    if(!r) 
    { 
     ReportError(); 
    } 
    return r 
} 

注意到,该表机制的工作方式与开关一样。只要所有的代码在systemNInit()功能发现(应该是),开关不添加任何东西,所以你可以做这样的事情太:

bool mainInit(int idx) 
{ 
    if(idx < 0 || idx >= sizeof(initialization_functions)/sizeof(initialization_functions[0])) 
    { 
     throw std::range_error("index out of bounds"); 
    } 
    if(!initialization_functions[idx]()) 
    { 
     ReportError(); 
     return false; 
    } 
    return true; 
} 

调用mainInit()使用索引可以如果有帮助你想“去初始化”正确:

int main() 
{ 
    for(size_t idx(0); idx < ...; ++idx) 
    { 
     if(!mainInit(idx)) 
     { 
      while(idx > 0) 
      { 
       --idx; 
       mainDeinit(idx); 
      } 
      exit(1); 
     } 
    } 
    ...app do something here... 
} 
0

有清楚的错误消息使用自定义异常,并添加周围的代码main()的try-catch-报告,死亡。例外情况是通过使“不良路径”隐含,使您的案例更加美观。

void initX() { ...; throw std::invalid_argument_exception("..."); } 

int main() { 
    try { 
     init1(); init2(); ... run(); 
     return 0; 
    } catch (std::exception const& e) { 
     log(e.what()); exit 42; 
    } 
} 
0

我会做这种方式:

bool mainInit() { 
    if (!system1Init()) { 
    return(false); 
    } 

    if (!system2Init()) { 
    return(false); 
    } 

    if (!system3Init()) { 
    return(false); 
    } 

    //...     

    return(true); 
} 

//... 

if(!mainInit()) { 
    reportError(); 
}