在下列情况下可以使用goto吗?

TX_*_*TX_ 1 c++

好的,世纪的问题:)

在你说或想什么之前,让我告诉你,我已经读过几个关于这个话题的类似问题,但是我没有找到解决问题的明确方法.我的案例是具体的,我认为是系统程序员的典型案例.

我经常遇到这种情况.我讨厌搞砸了,不知道为什么,可能是因为每个人都在大喊大叫它是坏事.但是直到现在我还没有找到更好的解决方案来解决我的特定场景,而我目前的做法可能比使用goto更难.

这是我的情况:我使用C++(Visual C++)进行Windows应用程序开发,而且我常常在我的例程中使用大量的API.假设以下情况:

int MyMemberFunction()
{
    // Some code... //

    if (!SomeApi())
    {
        // Cleanup code... //

        return -1;
    }

    // Some code... //

    if (!SomeOtherApi())
    {
        // Cleanup code... //

        return -2;
    }

    // Some more code... //

    if (!AnotherApi())
    {
        // Cleanup code... //

        return -3;
    }

    // More code here... //

    return 0; // Success
}
Run Code Online (Sandbox Code Playgroud)

因此,在每个Api之后我必须检查它是否成功,并且如果没有则中止我的功能.为此,我使用了大量的// Cleanup code... //,通常是重复的,然后是return声明.该功能执行10个任务(例如使用10个Apis),如果任务#6失败,我必须清理以前任务创建的资源.请注意,清理应该由函数本身完成,因此不能使用异常处理.另外,在这种情况下,我无法看到有多少谈论RAII可以帮助我.

我想到的唯一方法是使用goto从所有这些失败案例跳转到一个清理标签,放置在函数的末尾.

有没有更好的方法呢?在这种情况下使用goto会被认为是不好的做法吗?该怎么办?这种情况对我来说非常典型(对于像我这样的系统程序员,我相信).

PS:需要清理的资源属于不同类型.可能存在内存分配,需要关闭的各种系统对象句柄等.

更新:

我认为人们仍然没有得到我想要的东西(可能我解释得很糟糕).我认为伪代码应该足够了,但这是一个实际的例子:

  1. 我用CreateFile打开两个文件.如果此步骤失败:我必须清除已打开的文件句柄(如果有).我稍后会阅读一个文件的一部分并写入另一个文件.

  2. 我使用SetFilePointer将读指针放在第一个文件中.如果此步骤失败:我必须关闭上一步打开的句柄.

  3. 我使用GetFileSize来获取目标文件大小.如果api失败,或文件大小异常,我必须进行清理:与上一步相同.

  4. 我分配指定大小的缓冲区从第一个文件读取.如果内存分配失败,我必须再次关闭文件句柄.

  5. 我必须使用ReadFile从第一个文件中读取.如果失败,我必须:释放缓冲区内存,并关闭文件句柄.

  6. 我使用SetFilePointer将写指针放在第二个文件中.如果失败,则必须进行相同的清理.

  7. 我必须使用WriteFile写入第二个文件.如果失败了,bla-bla-bla ......

另外,假设我用关键部分保护这个函数,并且在EnterCriticalSection函数开头调用LeaveCriticalSection之后,我必须在每个return语句之前调用.

现在请注意,这是一个非常简化的示例.可能会有更多的资源和更多的清理工作 - 大多数相同,但有时会有所不同,这取决于哪个步骤失败了.但是让我们在这个例子中谈谈:我如何在这里使用RAII?

Alo*_*ave 7

goto不需要使用它,它容易出错,导致冗余且相当不安全的代码.

使用RAII,您不必使用goto.RAII通过智能指针非常适合您的场景.

您确保范围内的所有资源都是RAII管理的(使用智能指针或您自己的资源管理类),每当出现错误情况时,您只需返回并且RAII将神奇地释放您的资源.

  • @Corbin:我认为引用*性能问题*作为不使用RAII的原因是不正确的,除非代码在该特定系统上进行了分析,并证明瓶颈是*RAII.如果没有这样的分析,对RAII的批评是毫无根据的抨击. (3认同)