【问题标题】:Why are my C++ exceptions not being caught?为什么我的 C++ 异常没有被捕获?
【发布时间】:2010-11-25 12:52:05
【问题描述】:

我有一些使用非常标准异常模式的 C++ 代码:

try {
  // some code that throws a std::exception
}
catch (std::exception &e) {
  // handle the exception
}

问题是异常没有被捕获,我不知道为什么。

代码编译为 OS X 中的静态库(通过 Xcode)。该库链接到 Cocoa 应用程序,通过 Objective-C++ thunk 调用相关函数。我怀疑 Objective-C 和 C++ 之间的相互作用是罪魁祸首,但我所有试图确定这一点的尝试都失败了。

我无法创建一个在简单示例中重现此行为的简单示例。当我将相关代码从我的大程序的上下文中取出时,一切正常。

谁能指出为什么我的异常没有被捕获?

【问题讨论】:

  • 你有什么证据让你认为抛出了异常?你有什么证据表明它来自std::exception? (不是说你错了,但这里明显缺乏信息)
  • 对于从搜索中找到此内容的任何人,还要检查 (a) this other thread 和 (b) 您的 throw 没有埋在嵌套函数调用中,其中外部调用的权限较小异常规范,包括noexcept。如果正确指定了抛出函数,但它被 noexcept 函数(或不抛出被抛出的东西的函数)调用,则调用者将终止。这可能是基本的,但它只花了我几分钟的时间,所以!

标签: c++ objective-c exception-handling


【解决方案1】:

C++ allows you a variety of options for catching: value, reference or pointer. 请注意,此代码仅捕获通过引用或值传递的 std::exceptions:

try {
  // some code that throws a std::exception
}
catch (std::exception &e) {
  // handle the exception
}

很有可能是指针传递了异常:

catch (std::exception* e)

检查引发异常的代码,看看它是如何做到的。

正如 Mark 指出的那样,如果您通过值而不是通过引用来捕获,那么您可能会切割您的对象。

【讨论】:

  • 谢谢 - 这刚刚解决了我的问题。
  • 这个答案是一个很好的发现,来自 java/脚本语言背景自然假设异常总是按值传递。谢谢。
  • 对不起,这个答案是错误的。您可以按值或引用捕获异常,但它总是按值抛出 - catch 将正常工作。首选通过引用捕获以防止异常对象切片。抛出指针是完全不同的事情,因为std::exception* 是与std::exception 完全不同的类型。
  • @MarkRansom - 感谢您发现该错误。我更新了我的答案以删除提到通过引用投掷的文本。我不确定那天我在想什么。
  • @BenL:我强烈建议不要用指针扔。按值抛出,按常量引用捕获。
【解决方案2】:

尝试catch(...) {} 块,看看是否真的抛出异常。

【讨论】:

  • 我不明白这个答案 - 这个问题已经包含一个 catch() 块。
  • 该问题包括std::exception 类型异常的处理程序。使用省略号 (...) 作为 catch 参数的 catch 块将捕获任何异常,无论抛出异常的类型是什么。很像一个“默认”处理程序。
【解决方案3】:

我怀疑 Objective-C 和 C++ 之间的相互作用是罪魁祸首,但我所有试图确定这一点的尝试都失败了。

你可能是对的,虽然很难追查到。

首先,GCC 显式地does not allow you to throw exceptions in Objective C++ and catch them in C++ ("当从Objective-C++ 使用时,Objective-C 异常模型此时不与C++ 异常互操作。这意味着你不能@throw 来自Objective-C 的异常和@ 987654325@ 在 C++ 中,反之亦然(即,throw ... @catch)。”)

但是,我认为您正在描述一种情况,即 Objective C++ 调用 C++ 代码,C++ 代码抛出并且您希望 C++ 代码捕获异常。不幸的是,我很难找到这个特定案例的文档。有一些希望,因为“It is believed to be safe to throw a C++ exception from one file through another file compiled for the Java exception model, or vice versa, but there may be bugs in this area”。如果他们可以为 Java 做到这一点,那么他们就有机会为 Objective C++ 做到这一点。

至少,您需要在编译时指定-fexceptions(“在编译需要与用 C++ 编写的异常处理程序正确互操作的 C 代码时,您可能需要启用此选项”)。同样,这并没有特别提到 Objective C++,但它可能适用。

【讨论】:

    【解决方案4】:

    一个鲜为人知的带有异常的陷阱与基类的访问有关。

    如果您实际上抛出了一个从 std::exception 私有派生的类,则不会选择 std::exception 处理程序。

    例如:

    #include <iostream>
    
    class A { };
    class B : private A { } ;
    
    int main ()
    {
      try
      {
        throw B ();
      }
      catch (A & )
      {
        std::cout << "Caught an 'A'" << std::endl;
      }
      catch (B & )
      {
        std::cout << "Caught an 'B'" << std::endl;
      }
    }
    

    通常,这样的处理程序顺序会导致“B”处理程序永远不会被选中,但在这种情况下,“B”是从“A”私下派生的,因此类型“的捕获处理程序”不考虑 A'。

    【讨论】:

      【解决方案5】:

      我可以提供两种理论:

      1. 异常在你的catch子句出现之前被捕获;堆栈上的任何函数都可能是罪魁祸首。按照迈克尔的建议,试着抓住一切。
      2. 异常展开无法找到您的处理程序。要更详细地分析这一点,您将不得不逐步执行异常展开代码,这非常麻烦。查看使用 -fobjc-exceptions 编译 Objective-C 代码是否有帮助。

      【讨论】:

        【解决方案6】:

        这可能有点远,但在 Visual Studio 的编译器设置中,有一个选项可以完全关闭异常。也许在 GCC / XCode 中有类似的东西。

        【讨论】:

          【解决方案7】:

          C++ 异常几乎可以是任何东西,通常是char*。正如之前建议的那样,添加catch (...) 至少让它崩溃,看看发生了什么。

          【讨论】:

          • 我从未见过char* 异常,我会扇任何用过的人的耳光
          【解决方案8】:

          感谢大家的意见。对于遇到类似问题的任何人来说,这些都是很好的建议。它现在正在工作,但我不能 100% 确定我所做的各种更改中的哪一个导致事情再次变得理智。再一次,简化为可行的东西并从那里建立备份的方法得到了回报。

          回复中没有提到的一件事,我认为这是我困惑的一部分,那就是确保处理程序清楚地表明它确实捕获了异常。我认为在我对处理程序的一些表述中,它掩盖了这一事实并将异常传递给更高级别的处理程序。

          【讨论】:

            猜你喜欢
            • 2010-11-16
            • 2012-01-22
            • 1970-01-01
            • 2020-11-16
            • 2012-02-24
            • 2017-06-18
            • 1970-01-01
            相关资源
            最近更新 更多