c++ - 错误处理中如何避免goto

标签 c++ error-handling goto

我知道带有 goto 的程序是多么可怕和难以阅读,我想像其他人一样不惜一切代价避免使用它们。

但是,我遇到了一个情况,我在编写优雅的程序时很难避免它们。它带有错误处理。我做了很多步骤,如果任何一步出错,程序应该显示一条错误消息,释放一些内存并返回 false。如果一切正常,它应该返回 true

原程序是这样的:

bool init_routine()
{
     int errcode;   // Error code
     errcode = do_someting();
     if(errcode != RETURN_SUCCESS)
     {
         free_some_memory();
         std::cerr << "Something went wrong in initialization.";
         return false;
     }
     errcode = do_something_else();
     if(errcode != RETURN_SUCCESS)
     {
         free_some_more_memory();   // Was allocated in the do_something function
         free_some_memory();
         std::cerr << "Something went wrong in initialization.";
         return false;
     }
     /* The same pattern repeats quite a few times... */
     return true;   // Everything was ok
}

这很丑陋,因为有些代码是一遍又一遍地复制粘贴,这是不好的做法。我可以使用一个函数,但是该函数无法从被调用方返回 false,因为 C++ 缺少我所说的双重返回指令

另一种方法是使用嵌套的 if :

bool init_routine()
{
     int errcode;   // Error code
     errcode = do_someting();
     if(errcode == RETURN_SUCCESS)
     {
         errcode = do_something_else();
         if(errcode == RETURN_SUCCESS)
         {
             /* The same pattern repeats quite a few times */
             if()
             {
                if()
                {
                      if()
                      {
                         return true;
                      }
                }
             }
         }
         free_some_more_memory();
     }
     free_some_memory();
     std::cerr << "Something went wrong in initialization.";
     return false;
}

这避免了任何重复并且紧凑。但是,随着嵌套 if 的数量快速增长,缩进会成为阻碍。而且,所有那些if都隐藏了程序简单的控制流程,只是顺序执行指令,错误退出,让读者相信有很多复杂的条件可以遵循。

我认为更自然的另一种方式是:

bool init_routine()
{
     int errcode;   // Error code
     errcode = do_someting();
     if(errcode != RETURN_SUCCESS)
     {
         goto err1;
     }
     errcode = do_something_else();
     if(errcode != RETURN_SUCCESS)
     {
         goto err2;
     }
     /* The same pattern repeats quite a few times... */
     return true;   // Everything was ok

err2:
     free_some_more_memory();
err1:
     free_some_memory();
     std::cerr << "Something went wrong in initialization";
     return false;
}

没有重复,唯一的问题是使用了邪恶的goto。我的问题是:

有没有办法不使用 goto,同时不使用重复,不使用异常,并且没有疯狂的缩进?

编辑:为了清楚起见,我不能使用异常,因为我调用的例程来自用 C 编写的外部库,并且我从我的 C++ 代码中调用它们。很抱歉没有早点提到这一点。

最佳答案

如果您绝对必须显式分配,请使用标准集合或智能指针,例如 std::unique_ptr。他们自动进行重新分配。就是这样。

更一般地说,使用带有清理的析构函数的对象(标准集合和智能指针就是这样做的)。这就是众所周知的 RAII,资源获取即初始化。 Google 以了解更多信息,并在教科书的索引中查找。

顺便说一句,将输出混合到通用函数中并不是一个好主意。如果您想在 GUI 程序中使用该代码怎么办?

关于c++ - 错误处理中如何避免goto,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29230481/

相关文章:

c++ - 二进制搜索代码未通过效率检查

php - 引用 - 这个错误在 PHP 中意味着什么?

error-handling - 为什么我不能把左大括号放在下一行?

c - 转到函数外部嵌入式 C 中的行号

c++ - 从特定代码部分跳转到函数开始

java - 如何从 GLM 到 JOML(OpenGL 数学库)

c++ - 重载函数和继承

c++ - 无法在动态链接库中找到过程入口点 clCreateCommandQueueWithProperties

python - 使用 django 将值保存在数据库中

c - 为什么有些内核程序员使用 goto 而不是简单的 while 循环?