Goto sleep:去还是不去 (c++ goto)

目前我正在研究一个项目,其中 goto 语句被大量使用。goto 语句的主要目的是在一个例程中有一个清理部分,而不是多个 return 语句。像下面这样:

BOOL foo()
{
   BOOL bRetVal = FALSE;
   int *p = NULL;
   p = new int;
   if (p == NULL)
   {
     cout<<" OOM \n";
     goto Exit;
   }
   // Lot of code...
Exit:
   if(p)
   {
     delete p;
     p = NULL;
   }
   return bRetVal;
}

这使得它更容易,因为我们可以在代码中的一个部分跟踪我们的清理代码,即在退出标签之后。

然而,我读过很多地方,有 goto 语句是不好的做法。

目前我正在阅读Code Complete书,它说我们需要使用接近其声明的变量。如果我们使用 goto,那么我们需要在首次使用 goto 之前声明 / 初始化所有变量,否则编译器会给出错误,即 goto 语句跳过了 xx 变量的初始化。

哪条路是对的?

斯科特的评论:

它看起来像使用 goto 从一个部分跳转到另一个部分是不好的,因为它使代码难以阅读和理解。

但是,如果我们使用 goto 只是为了前进和一个标签,那么它应该是好的(?)。

60

我不知道你的意思是清理代码,但在 C ++ 中有一个概念称为“资源获取是初始化”,它应该是你的析构函数清理东西的责任。

(请注意,在 C # 和 Java 中,这通常是通过 try / finally 解决的)

有关详细信息,请查看此页面:http://www.research.att.com/~bs/bs_faq2.html#finally

编辑:让我澄清一下。

考虑以下代码:

void MyMethod()
{
    MyCl *myInstance = new MyCl("myParameter");
    /* Your code here */
    delete myInstance;
}

问题:如果函数有多个出口,会发生什么?您必须跟踪每个出口,并在所有可能的出口删除您的对象!否则,您将有内存泄漏和僵尸资源,对吗?

解决方案:使用对象引用,因为当控件离开范围时,它们会自动清理。

void MyMethod()
{
    MyCl myInstance("myParameter");
    /* Your code here */
    /* You don't need delete - myInstance will be destructed and deleted
     * automatically on function exit */
}

哦,是的,并使用std::unique_ptr或类似的东西,因为上面的例子显然是不完美的。

60

我从来没有在 C++ 中使用过 goto。ever。ever。如果有一种情况应该使用它,这是非常罕见的。如果你真的在考虑把 goto 作为你逻辑的标准部分,有些东西已经偏离了轨道。

22

人们对 gotos 和您的代码基本上有两点:

Goto 很糟糕。很少遇到需要 gotos 的地方,但我不建议完全解决它。尽管 C ++ 具有足够智能的控制流,使 goto 很少合适。

那么您的清理机制是错误的:这一点更为重要。在 C 中,自己使用内存管理不仅可以,而且通常是最好的方法。在 C ++ 中,您的目标应该是尽可能避免内存管理。您应该尽可能避免内存管理。让编译器为您做。而不是使用new时,只需声明变量即可。

如果您合法地需要内存管理(您没有真正提供任何证据),那么您应该通过构造函数将您的内存管理封装在一个类中,以分配内存和解构函数来释放内存。

您的回应是,从长远来看,您的做事方式要容易得多,这并不是真的。首先,一旦您对 C ++ 产生强烈的感觉,制作这样的构造函数将是第二天性。就个人而言,我发现使用构造函数比使用清理代码更容易,因为我不需要仔细注意以确保我正确地释放。相反,我可以让对象离开范围,语言为我处理它。此外,维护它们比维护更容易

简而言之,goto在某些情况下可能是一个不错的选择,但在这种情况下不是。

20

你的代码是非常非惯用的,你不应该写它。你基本上是在 C ++ 中模拟 C。但是其他人已经评论过了,并指出 RAII 是替代方案。

但是,您的代码不会像您期望的那样工作,因为这样:

p = new int;
if(p==NULL) { … }

不会使用ever,而是将其评估为true的昂贵版本(除非您以奇怪的方式重载了operator new)。如果operator new无法分配足够的内存,则会引发异常,它永远返回0,至少在这组特殊参数下不会引发异常。

您的delete块也是如此,正如 Harald 所说:if (p)delete p前面是不必要的。

此外,我不知道你的例子是故意选择的,因为这个代码可以重写如下:

bool foo() // prefer native types to BOOL, if possible
{
    bool ret = false;
    int i;
    // Lots of code.
    return ret;
}

本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处

(811)
Catti笔译二级含金量:Kotlin二级构造函数
上一篇
Coursera吴恩达:吴恩达机器学习课程第二周怎么解决 在 matlab上提交作业
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(87条)