使用goto设想跳过代码而不使用状态变量

时间:2014-05-23 20:20:30

标签: c++ c goto

我有一个代码,如果代码之前有错误,那么这些代码必须执行。我实际上使用了一个名为EndProg的bool变量,如果设置为true,它将指示程序避免执行某些代码部分。

我的问题是我不想使用这种方法而我更喜欢使用goto,因为它会使程序跳转到清理部分并避免检查{{1多次重复值。

另一个问题是我在StackOverflow和其他使用EndProg的网站上的许多页面上阅读被认为是一种不好的做法,并且它可能使代码更难以阅读或创建错误。< / p>

我的代码很简单,我只需要使用一个标签,所以我怀疑这会产生问题;但是我想知道是否有其他方法可以做我想要的而不创建执行清理任务或使用goto的函数(因为,例如,我需要多次编写清理代码)而且我也不想在多个地方编写相同的大清理代码,然后使用return或做其他事情。

我不想增加代码行数,也不想使用return,也不想使用大量return,也不要检查状态变量的值。你会推荐什么?

这是一段代码:

if

我想做的是:

bool EndProg=false;
/*
    Lot of code that can set EndProg to true
*/
ClassType ClassName;
if(!EndProg && LoadConf(&ConfFilePath,&ClassName)==0)
{
    int fildes=-1;
    if(ClassName.abc) // bool
    {
        if(ClassName.FilePath==0) // char *
        {
            ClassName.FilePath=new(std::nothrow) char[9]();
            if(ClassName.FilePath!=0)strcpy(ClassName.FilePath,"file.ext");
            else EndProg=true;
        }
        if(!EndProg && mkfifo(ClassName.FilePath,S_IRUSR | S_IWUSR)==-1)
        {
            if(errno==EEXIST)
            {
                /* EEXIST is returned if the file already exists
                We continue, later we will try to open this file */
            }
            else EndProg=true;
        }
        if(!EndProg && (fildes=open(ClassName.FilePath,O_RDWR))==-1)EndProg=true;
    }
    /*
    Lot of code that will check if EndProg == true
    */
}
delete[] ClassName.FilePath;
delete[] ConfFilePath;

正如您所看到的那样,它并不难理解,即使搜索标签对某人来说也是一个问题,但对我来说并非如此;而且我不打算公开代码。

更新:

我决定使用异常,它适用于原始代码的某些部分。但我怀疑这将更容易在更复杂的部分实施。谢谢你的回答。

4 个答案:

答案 0 :(得分:6)

由于您已对此问题c++进行了标记,因此我还要使用例外和try catch阻止。

您可以在SO和其他网站上找到有关该主题的大量有用信息:

这是一个非常基本的tutorial

这是一个很好的基本FAQ,也可以帮助你。

基本上没有什么可担心的,例外不是神秘的,事实上当你掌握它时更有意义。因为基本上这个概念可以让你完全达到你想要的目的:

相同的错误处理代码可以处理几个陷阱。

修改: 例如,如果我将mkfifo等移动到一个函数中(通常为每个定义良好的逻辑块创建一个函数更清晰,更具可读性)并且具有类似的内容

这只是一个草图,可以为您提供一般概念:

#include <exception>


functionThatDoesMakeFifo(...){
   // check which ever conditions you want to check after mkfifo
   // if one of them goes wrong just do:
   throw std::exception();

}

// this is inside your function:
   ClassType ClassName;       
   try{
      ClassName.FilePath = new char[9](); // even though I'd use a string...
      .
      .
      . // rest of the code
   } catch(std::exception &e){    
       delete [] ClassName.FilePath;
       delete [] ConfFilePath;
       ClassName.FilePath = NULL; // not mandatory just my habit
       ConfFilePath = NULL;
   }

答案 1 :(得分:1)

我会尝试使用Scope GuardsBOOST_SCOPE_EXIT(C ++)或its C++11 analogue之类的内容:

template<class F>
struct ScopeExit
{
  ScopeExit(F f) : f(f) {}
  ~ScopeExit() { f(); }
  F f;
};

template<class F>
ScopeExit<F> MakeScopeExit(F f) { return ScopeExit<F>(f); }

#define STRING_JOIN2(arg1, arg2) DO_STRING_JOIN2(arg1, arg2)
#define DO_STRING_JOIN2(arg1, arg2) arg1 ## arg2
#define SCOPE_EXIT(code) \
  auto STRING_JOIN2(scope_exit_, __LINE__) = MakeScopeExit([=](){code;})


bool myfunct()
{
  ClassType ClassName;

  ClassName.FilePath = 0;
  ConfFilePath = 0;
  SCOPE_EXIT(delete [] ClassName.FilePath; delete [] ConfFilePath; );

  if (LoadConf(&ConfFilePath,&ClassName) == 0)
  {
    int fildes=-1;
    if(ClassName.abc) // bool
    {
      if(ClassName.FilePath==0) // char *
      {
        ClassName.FilePath=new(std::nothrow) char[9]();
        if(ClassName.FilePath==0) return false;
        strcpy(ClassName.FilePath,"file.ext");
      }
      if(mkfifo(ClassName.FilePath,S_IRUSR | S_IWUSR)==-1)
      {
        if (errno==EEXIST)
        {
          /* EEXIST is returned if the file already exists
          We continue, later we will try to open this file */
        }
        else return false;
      }
      if((fildes=open(ClassName.FilePath,O_RDWR))==-1) return false;
    }
    /*
    Lot of code that will check if EndProg == true
    */
  }

  return true;
}

我正在使用return,但清理代码只在一个地方。

无论如何ClassName应该在析构函数中清理自己的资源。

答案 2 :(得分:0)

我之前看到的一个小技巧可能会帮助你解决这个问题,虽然我个人不是技巧的粉丝,但它可能适合你的需要。

while (true)
{
    if(ClassName.FilePath==0) // char *
    {
        ClassName.FilePath=new(std::nothrow) char[9]();
        if(ClassName.FilePath==0) break;
        strcpy(ClassName.FilePath,"file.ext");
    }
    if(mkfifo(ClassName.FilePath,S_IRUSR | S_IWUSR)==-1)
    {
        if(errno==EEXIST)
        {
            /* EEXIST is returned if the file already exists
            We continue, later we will try to open this file */
        }
        else break;
    }
    if((fildes=open(ClassName.FilePath,O_RDWR))==-1) break;
    /*
    Lot of code that will check if EndProg == true
    */
    break;
}

delete[] ClassName.FilePath;
delete[] ConfFilePath;

但我再次强调这不是一个优雅的解决方案,我个人会重新编写你的代码并将其分解为更具可读性的东西。 但是,我再也不会编写包含数百行的函数。

答案 3 :(得分:0)

我可能会因此而被投票,但我认为在C中限制使用goto并不是邪恶的。特别是,您所谈论的内容是完全可以接受的:分支前进以清除错误代码。我建议你将每个例程限制为一个目标标签。

人们讨厌的(理所当然的)是古老的意大利面条代码,goto在各处跳跃。