【问题标题】:Catch statements are being completely ignoredCatch 语句被完全忽略
【发布时间】:2011-10-19 05:52:07
【问题描述】:

我遇到了一些我继承的代码的情况......老实说,我相信代码编写正确,但这个错误似乎仍然存在。

我会很快注意到代码是从 linux 交叉编译到 LynxOS,我不确定这是否与错误有关。

基本上,在一种特定情况下:

try {
    std::vector<ClassA> x = SomeGeneratingFunction();

    //We get to here fine.  X may be empty/unpopulated though.
    if (x.size() < 1)
    {
        throw(MyException("It crashed."));
    }
}
catch (MyException e)
{
    //Handle it.
}
catch (...)
{
    //Handle it.
}

鉴于向量未填充,我们 throw ,但由于某种原因,throw 绕过了 catch 子句——它们两者。它似乎只发生在这里 - 虽然我们通常不会在 if 语句范围内这样做,但这应该是完全不相关的,因为它仍在 try 范围内。

PS:下面的代码实际上是一个函数的内容,调用的时候会出现异常,尽管它们都应该由catch块处理。

您有什么想法吗?是的,这不是真正的代码/异常类,但异常类是您搜索的重载 std::exception 的简单示例,并且 SomeGeneratingFunction() 确实返回了一个好的向量,即使它是空的。我无法提供真正的代码,但除非我在脑海中写下任何小错别字,否则这非常接近。

【问题讨论】:

  • 我不知道,但考虑将 catch 行写成 catch (const MyException& e) 以避免为 MyException 复制构造函数付费,因为您将获得throw 扔了。
  • 如果你添加调试语句(在条件之前,在抛出之前和之后)它会改变行为吗?如果你把矢量从图片中取出怎么办?当你使用 'catch throw' 运行时,GDB 会做什么?你如何编译?尝试使用优化标志进行处理
  • 调试语句按预期打印,不会改变行为。这是一个庞大的系统,具有复杂的 make 层次结构和在不同部分使用的许多标志 - 但更重要的是,我们在您应该(或尝试)的任何地方都使用 try catch 并且以前从未见过这种情况。我想也许交叉编译器可能会弄乱范围或类似的东西,但我对编译器知之甚少。我已经让几个人看过了——我们可以通过 if else 而不是 if/throw 来解决它,但是解决一些不应该发生的事情是令人担忧的
  • 另外,你可以试试x.empty() 而不是x.size() &lt; 1
  • 这里没有足够的信息来回答这个问题。我将发布的代码推送到 main 函数中,添加了一些 #includeMyExceptionClassASomeGeneratingFunctioncatch 的一些最小定义@ 对我来说按预期工作。

标签: c++ exception


【解决方案1】:

由于catch (...) 子句没有捕捉到异常,我的回答并没有解决 OP 的问题。但是对于在 SO 上发现这个问题的其他人,也许我的回答很有用,因为它解释了为什么第一次捕获失败。

我遇到了类似的问题,我的 catch(const std::exception&amp; ex) 无法正常工作。结果证明这是一个愚蠢的问题,因为我在 C# 和 C++ 异常之间切换,并且在 C# 中你需要在抛出异常时指定 new,而在 C++ 中你通常不需要(但你可以,但在在这种情况下,您抛出的是指针而不是引用)。我不小心做了

throw new std::runtime_error("foo");

所以

catch(std::exception*  ex)

会抓住它,但是

catch(std::exception& ex)

没有。当然,解决方法就是去掉 new 语句,因为这不是 C++ 中的传统设计模式。

【讨论】:

  • 我的代码中出现了完全相同的问题!一直在谷歌上搜索可能的原因很长时间,最终结果是你提到的同样愚蠢的错误。
【解决方案2】:

由于在throw 语句中的异常对象周围有一组备用括号,它看起来像一个函数调用。您是否有可能定义了一个名为throw 的函数?异常构造函数的参数可防止它成为Most Vexing Parse 的受害者,但如果您的实际代码与您的示例不同,则有可能发生这种情况。

【讨论】:

  • throw 是关键字,您不能使用该名称定义函数。
  • throw MyException()throw(MyException()) 不可能是一个令人烦恼的解析,因为 throw 是一个关键字,而不是类型名称。如果您尝试使用 throw 作为函数的名称,我不知道有任何 C++ 编译器不会抱怨。
  • @interjay 我想过这个问题,但也许有一些不正常的情况,throw 被宏重新定义了?我同意它正在抓住稻草,但绝望的问题需要绝望的解决方案。
  • 嗯,我喜欢这个主意。我确实认为它在这一点上与交叉编译存在某种编译器故障。我有很多非常有能力的人检查它无济于事。无论如何,我尝试了你的建议,但它似乎没有改变任何东西 - 但谢谢你,这是一个有趣的想法! :) 我可能无法解决这个问题,但无论如何我会再搁置一段时间。
【解决方案3】:
catch (MyException e)

应改为:

catch (const MyException &e)

我也不确定为什么你的 throw 看起来像一个函数,有点奇怪。

编辑:

我遇到过基于类似问题的问题,但我同意在这个玩具箱中这还不够。

编译器在我看来是不对的,Try 被定义为有趣的东西吗?如果它是空的,可能如果你的编译器忽略了没有尝试的 catch 语句。

【讨论】:

  • 这不是通过阻止副本的形成来提高效率吗?或者如果没有它,原始异常实际上会从函数中传播出去吗?
  • 如果MyException 不可复制,这可能是问题(尽管编译器可能需要为此发出诊断),但我认为这是极不可能。 (哦,通过const 引用更好。)
  • 通过引用捕获可能是一种更好的做法(正如@sbi 指出的那样,在这种情况下它应该是catch (const MyException &amp;e)),这不是最初的问题。
  • @w00te:如果您不通过引用捕获,您很容易受到切片问题的影响。这是当一个派生自 MyException 的类被抛出并随后被 MyException 的值捕获时,生成的复制构造将从对象中切出派生部分。
  • @sbi,如果 MyException 不可复制,您将无法 throw 它。 throw 总是复制一份。
【解决方案4】:

如果您有一个 函数 MyException 在较小的范围内(甚至可能是偶然的,Most Vexing Parse),那么 throw MyException("It crashed") 将调用该函数并抛出返回值。

【讨论】:

    【解决方案5】:

    让我来解决这个问题...不要在 C++ 中使用异常,除非您确实想使程序崩溃。我知道异常可能非常有用,但是它们的性能很差,因为它会引发一个硬件异常,该异常会被操作系统内核捕获。使用返回值和错误代码可以比抛出和捕获异常快 500 倍。

    【讨论】:

    • 为什么?这是一个设计建议。我做了基准测试来验证这一点,我团队的另一位程序员确实查看了生成的程序集以了解异常机制。我们的发现可能令人惊讶,但问题很严重。
    • 更快并不是更稳定的代名词。
    • 可以创建智能结构来检查是否已读取错误代码。使用该机制,您具有与异常相同的稳定性。另外,在另一个异常处理期间抛出异常时,可能很难跟踪错误。关于性能,如果不抛出异常,它们不会增加任何开销 - 但是,例如使用异常来检查用户输入的正确性是一个糟糕的设计。异常必须只是“例外”,并尽可能避免。
    【解决方案6】:

    我只是重写它而不使用 try/catch。无论如何,这里似乎不适合使用 try/catch。众所周知,异常可能不适用于您的目标平台。

    【讨论】:

    • 这就是我所做的,但我想了解它们的问题所在,因为它们已在许多其他地方使用并且似乎工作正常 - 可能需要调整其他代码。
    • 这并不能真正解决我的问题,但这是我最终必须做的事情,所以我会标记它,哈哈。用我认为有帮助的信息标记其他答案。
    • 根本没有解决 OP 的问题。
    猜你喜欢
    • 1970-01-01
    • 2021-10-22
    • 2012-11-19
    • 2017-09-22
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 2015-08-13
    • 2014-03-04
    相关资源
    最近更新 更多