10

我正在开发一个性能关键的动态链接库 (DLL),它也应该具有相对较小的二进制大小。由于它没有明确抛出任何异常,我想完全禁用异常支持。但是,有一个例外(双关语意外):当内存不足 (OOM) 时,我必须向应用程序报告错误代码,以便它有机会优雅地处理事情。代码库太大,无法单独检查每个分配并传播错误,并且包含我不应该接触的外部代码。所以我想在我的 DLL 导出函数中捕获 OOM 异常。

一个快速测试表明,当在 Visual C++ 2010 中禁用 C++ 异常(即没有 /EHa、/EHsc 或 /EHs 标志)时,它仍然会在分配过多内存时跳转到 catch(std::bad_alloc&) 块。

所以它似乎按预期工作。但是,我收到以下 1 级警告:“C4530:使用了 C++ 异常处理程序,但未启用展开语义。指定 /EHsc”。MSDN 说“在框架中自动存储的对象,在执行投掷的函数和捕获投掷的函数之间,不会被破坏”。

我会在这里失去什么?只要可以删除通过库创建的任何内容,并且应用程序可以重新开始(如果它愿意),就可以将事物置于未定义状态。是否存在无法恢复的泄漏内存的大风险?

DLL 是否使用单独的内存池?如果是这样,我可以在不需要应用程序卸载 DLL 的情况下清除它吗?我可以轻松地让我的库忽略任何进一步的(导出的)函数调用,直到应用程序执行重新初始化。

谢谢你的建议。

4

1 回答 1

1

一些预备知识:

我不知道在未启用异常处理的情况下抛出异常是否是未定义的行为或不符合标准,但您肯定不会从堆栈上的对象中获取堆栈展开/析构函数调用。

如果您使用 RAII 为互斥锁、文件、内存等编写 C++ 风格的代码,这是一件非常糟糕的事情。

然后继续,假设您的代码本质上是 C 风格的代码:

1) 如果您静态链接到 C 运行时库,您的 DLL 将不会与您的主应用程序共享堆。卸载 DLL 应该会释放泄漏的内存——但同样,请注意其他资源。

2)如果您动态链接到 C 运行时(很常见),那么您正在共享一个堆。您必须有一种方法来手动释放从 DLL 分配的任何内存。

让我自己在 DLL 边界问题上纠缠不清,我建议您进行快速基准测试,以了解您在启用异常方面付出的代价。根据您的平台和编译器,未引发的异常对性能的影响可以忽略不计。

于 2013-02-07T00:48:02.003 回答