我已经阅读了很多关于不应该在一个DLL中分配堆内存并从该DLL之外进行释放的事情。但是抛出一个仅仅是临时(大多数异常对象都是如此)的异常对象呢?例如:
throw my_exception( args ); // temporary: no heap allocation
当异常对象在 DLL 外部被捕获时,该对象的析构函数最终会被执行,非堆内存会被回收。由于它不是堆内存,所以这样做是否可以?
在跨DLL边界抛出C++异常只有当所有模块使用相同的C++运行时库时才可能,这样它们也共享一个堆。但是这可能会增加维护负担,特别是涉及多个供应商的库时,因此不建议使用。
如果您想要跨多个编译器/编译器版本/编译器设置具有可移植性的错误处理,可以使用返回代码或操作系统提供的异常(例如Windows上的SEH)。
这取决于内存是如何分配的,以及执行此操作的机制(“运行时”或“内存管理器”)是否在特定DLL和应用程序的其他部分之间共享。例如,根据详细信息,也可以使用throw new my_exception(args);
。
您可以使您的异常引用计数,以便它具有销毁自己实例(和拥有的内存)的固有知识。
例如,使用IMalloc
(请参见MSDN)进行实例分配和放置new
是另一种方法(在之前调用OleInitialize
)...
事实上,内存分配是一个问题,具体取决于正在使用的内容。例如,在应用程序的不同部分中混合静态链接CRT和动态链接CRT将导致问题,就像混合调试和发布代码一样。问题在于用于释放内存的代码使用了不同的“内存管理器”。但是,如果抛出的对象知道自己的销毁方式,那么就没问题,因为dtor代码将驻留在分配它的编译单元中。
15.1 抛出异常
,3:throw表达式初始化一个临时对象...
,5:异常对象的内存以一种未指定的方式分配...
@Paul:5:当被抛出的对象是类对象时,即使复制/移动操作被省略,复制/移动构造函数和析构函数也必须可访问。
- Eugen Constantin Dinca15.3处理异常
16:在异常声明中声明的对象或者如果异常声明没有指定名称,则从异常对象复制初始化一个临时对象(12.2)...
17:...当处理程序声明对非常量对象的引用时,对所引用对象的任何更改都是对在执行throw表达式时初始化的临时对象的更改,并且如果重新抛出该对象,则会产生影响。
- Eugen Constantin Dinca