如何在禁用C++异常(VS2010)的情况下确保内存不足的可靠性?

Nic*_*ens 10 c++ dll exception out-of-memory robustness

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

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

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

究竟我会在这里失去什么?只要通过库创建的任何内容都可以删除,并且应用程序可以重新开始(如果它选择的话),可以将事物保留在未定义状态.是否存在无法恢复的内存泄漏风险?

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

谢谢你的建议.

小智 1

一些预备知识:

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

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

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

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

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

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