1

我遇到过这样一种情况,我有一堆需要按顺序初始化的“系统”,只有在所有进行中的系统都成功初始化后,下一个系统才会被初始化。

这导致我使用大量嵌套的 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;
        }
    // ....
}

现在,我更喜欢这个了。我发现它更容易阅读,尤其是一些不错的评论,但我对编程还很陌生。

所以,我的问题是:看看这不是传统上使用 switch 语句的方式(至少从我所见),这样的事情是否可以接受,或者这会被认为是不好的形式?

作为编程新手,我尽量不养成太多坏习惯,这些习惯可能会让其他程序员感到沮丧并使事情变得更加困难。

我进行了搜索,但我发现的大部分内容都与替换 if - else if 语句的链有关,而不是替换嵌套的语句。

4

4 回答 4

3

引用数组中的所有系统,例如 an std::vector<mySystem*>,并按顺序循环它们,在第一次失败时中断。这样,您的整个代码将减少到不到 5 行代码,即使对于 500 多个系统也是如此。

建议的 switch hack 是解决 XY 问题的一个邪恶示例:您的真正问题是您没有系统数组,并且正在使用命名变量,因此消除了所有选项以更灵活地使用所有系统,例如在循环中。

于 2014-09-27T21:08:45.360 回答
0

使用带有明确错误消息的自定义异常,并在main(). 例外情况是通过隐含“坏路径”来专门使您的案例看起来不错。

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;
    }
}
于 2014-09-27T22:14:47.643 回答
0

我会这样做:

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

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

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

  //...                 

  return(true);
}

//...

if(!mainInit()) {
  reportError();
}
于 2014-09-27T22:40:35.773 回答
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...
}
于 2014-09-27T22:04:43.117 回答