代码之家  ›  专栏  ›  技术社区  ›  Anycorn

C++,这是GOTO语句的保证吗?

  •  9
  • Anycorn  · 技术社区  · 15 年前

    我稍微改变了标题,因为我认为这是更合适的问题。

    你会重构它吗(看起来像合法使用goto)? 如果,如何重构以下代码以删除go to语句?

    if (data.device) {
        try {
            ...
        }
        catch(const std::exception&) { goto done; }
        ... // more things which should not be caught
    done: ;
    }
    

    完整的陈述

    #ifdef HAVE_GPU
                // attempt to use GPU device
                if (data.device) {
                    try {
                        Integral::Gpu eri(S, R, Q, block.shell());
                        eri(basis.centers(), quartets, data.device);
                    }
                    // if GPU fails, propagate to cpu
                    catch(std::exception) { goto done; }
                    data.device += size;
                    host_index.extend(block_index);
                    block_index.data.clear();
                done: ;
                }
    #endif
    

    谢谢您

    在看到大多数人的偏好后,我决定和国旗一起去,但约克先生的评论。

    谢谢大家

    14 回复  |  直到 15 年前
        1
  •  15
  •   Amardeep AC9MF    15 年前
    if (data.device)
    {
        bool status = true;
    
        try
        {
            ...
        }
        catch(std::exception)
        {
            status = false;
        }
    
        if (status)
        {
        ... // more things which should not be caught
        }
    }
    
        2
  •  8
  •   user395760    15 年前

    第一:Goto本身并不邪恶。为了代码中没有字母“goto”而进行重构是无稽之谈。把它重构成比goto更干净的东西是可以的。把一个糟糕的设计变成一个更好的设计,而不需要Goto或是替代品,也很好。

    尽管如此,我还是要说你的代码看起来和最终发明的完全一样。太伤心的C++没有这样的东西…所以也许最简单的解决办法就是像这样离开。

        3
  •  7
  •   James McNellis    15 年前

    您可以捕获异常并重新引发一个可以在条件块之外处理的特定异常。

    // obviously you would want to name this appropriately...
    struct specific_exception : std::exception { };
    
    try {
        if (data.device) {
            try {
                // ...
            }
            catch(const std::exception&) { 
                throw specific_exception(); 
            }
    
            // ... more things which should not be caught ...
        }
    }
    catch (const specific_exception&) { 
        // handle exception
    }
    
        4
  •  4
  •   Jeff Paquette    15 年前

    为什么不在try块中移动额外的代码?:

    #ifdef HAVE_GPU
                // attempt to use GPU device
                if (data.device) {
                    try {
                        Integral::Gpu eri(S, R, Q, block.shell());
                        eri(basis.centers(), quartets, data.device);
                        data.device += size;
                        host_index.extend(block_index);
                        block_index.data.clear();
                    }
                    // if GPU fails, propagate to cpu
                    catch(std::exception) { /* handle your exception */; }
                }
    #endif
    
        5
  •  4
  •   Steve Jessop    15 年前

    标志的用法稍有不同。我觉得它比阿马尔代夫的要干净。

    我宁愿使用一个标志来指示是否传播异常,而不使用一个标志来指示最后一件事是否有效,因为 整点 例外的情况是避免检查最后一件事是否有效——我们的想法是编写代码,这样如果我们做到了这一点,那么所有的事情都会成功,并且我们可以继续下去。

    #ifdef HAVE_GPU
        // attempt to use GPU device
        if (data.device) {
            bool dont_catch = false;
            try {
                ...
                dont_catch = true;
                ... // more things which should not be caught
            } catch (...) {
                if (dont_catch) throw;
            }
        }
    #endif
    
        6
  •  4
  •   Community Mohan Dere    9 年前

    我想这方面的变种可能对你有用。

    // attempt to use GPU device
    if (data.device)
    {
        try
        {
            Integral::Gpu eri(S, R, Q, block.shell());
            eri(basis.centers(), quartets, data.device);
    
            data.device += size;
            host_index.extend(block_index);
            block_index.data.clear();
        }
        catch (const std::bad_alloc&)
        {
            // this failure was not because 
            // of the GPU, let it propagate
            throw;
        }
        catch(...)
        {
            // handle any other exceptions by
            // knowing it was the GPU and we 
            // can fall back onto the CPU.
        }
    }
    
    // do CPU
    

    如果您可以编辑GPU库并为所有GPU异常提供一些基础,比如 gpu_exception 代码变得更简单:

    // attempt to use GPU device
    if (data.device)
    {
        try
        {
            Integral::Gpu eri(S, R, Q, block.shell());
            eri(basis.centers(), quartets, data.device);
    
            data.device += size;
            host_index.extend(block_index);
            block_index.data.clear();
        }
        catch (const gpu_exception&)
        {
            // handle GPU exceptions by
            // doing nothing and falling
            // back onto the CPU.
        }
    
        // all other exceptions, not being 
        // GPU caused, may propagate normally
    }
    
    // do CPU
    

    如果不是这些工作,我想接下来最好的是 Steve's answer .

        7
  •  3
  •   Scott Saunders    15 年前
    if (data.device) {
        bool ok = true;
        try {
            ...
        }
        catch(std::exception) { ok = false; }
    
        if(ok) {
            ... // more things which should not be caught
        }
    }
    
        8
  •  2
  •   djna    15 年前

    你不能在国际单项体育联合会之外抓住例外吗?

        9
  •  2
  •   supercat    15 年前

    当有一堆代码需要基于某种条件退出时,我的首选构造是使用“do while(0)”循环,并在适当时使用“break”。我不知道该怎么休息;不过,在一次接球中会怎样。如果“休息”不起作用,“去”可能是你最好的选择。

        10
  •  2
  •   Nick Meyer    15 年前

    我是否遗漏了什么,或者它是否等同于在 catch done: 标签位于 try 街区?

    #ifdef HAVE_GPU
                // attempt to use GPU device
                if (data.device) {
                    try {
                        Integral::Gpu eri(S, R, Q, block.shell());
                        eri(basis.centers(), quartets, data.device);
                        data.device += size;
                        host_index.extend(block_index);
                        block_index.data.clear();
                    }
                    // if GPU fails, propagate to cpu
                    catch(std::exception) {}
                }
    #endif
    
        11
  •  1
  •   TJ Koblentz    15 年前

    使用一些标志并添加条件语句怎么样?

    int caught = 0;
    if (data.device) {
        try {
            /* ... */
        } catch (std::exception e) { caught = 1; }
        if (!caught) {
            // more stuff here
        }
        // done: ...
    }
    
        12
  •  1
  •   Kevin Anderson    15 年前

    把它分解成它自己的函数/方法(包括它之后的所有内容),然后使用 return 关键字。只要你的所有变量都有析构函数,都有栈分配(或者如果不可避免的话智能指针),那么你就可以了。我非常喜欢早期退出功能/方法,而不是连续的标志检查。

    例如:

    void myFunc()
    {
        String mystr("heya");
        try
        {
            couldThrow(mystr);
        }
        catch(MyException& ex)
        {
            return; // String mystr is freed upon returning
        }
    
        // Only execute here if no exceptions above
        doStuff();
    }
    

    这样很难出错

        13
  •  1
  •   Justin Ardini    15 年前
    catch(std::exception) { return; }
    

    这应该能解决问题。当然,我是这样想的 done 实际上是在函数的末尾。

    如果您需要在异常发生时执行额外的代码,请返回一个状态或抛出一个处于更适当抽象级别的异常(请参阅james的答案)。

    我想象的是:

    doStuff(...) {
        bool gpuSuccess = doGPUStuff(...);
        if (!gpuSuccess) {
            doCPUStuff(...);
        }
    }
    
        14
  •  1
  •   Stack Overflow is garbage    15 年前

    Goto今天不高兴的原因是我们有这些被称为“函数”的奇妙事物。将GPU代码包装在自己的函数中,如果失败,该函数可以提前返回。

    然后从原始函数调用它。

    因为他们可能需要共享一些变量( data , host_index block_index ,它看起来像),将它们放到一个类中,并使它的两个函数成为它的成员。

    void RunOnGpu(){
            // attempt to use GPU device
            if (data.device) {
                try {
                    Integral::Gpu eri(S, R, Q, block.shell());
                    eri(basis.centers(), quartets, data.device);
                }
                // if GPU fails, propagate to cpu
                catch(std::exception) { return; }
                data.device += size;
                host_index.extend(block_index);
                block_index.data.clear();     
    }
    void DoStuff() {
    #ifdef HAVE_GPU
        RunOnGpu();
    #endif
    }