C++ 投掷C++;跨DLL边界的异常

C++ 投掷C++;跨DLL边界的异常,c++,dll,exception-handling,C++,Dll,Exception Handling,我读过很多关于如何不在一个DLL中分配堆内存并从该DLL外部取消分配它的内容。但是抛出一个只是临时的异常对象(就像大多数异常对象一样)怎么样?例如: 当在DLL外部捕获异常对象时,该对象的析构函数最终将被执行,对象的非堆内存将被回收。因为它不是堆内存,所以可以吗?这取决于如何分配内存,以及这样做的机制(“运行时”或“内存管理器”)是否在特定DLL和应用程序的其他部分之间共享。例如,抛出新的my_异常(args)也可以按顺序排列,具体取决于详细信息 您可以对异常引用进行计数,这样它就具备了如何销毁

我读过很多关于如何不在一个DLL中分配堆内存并从该DLL外部取消分配它的内容。但是抛出一个只是临时的异常对象(就像大多数异常对象一样)怎么样?例如:


当在DLL外部捕获异常对象时,该对象的析构函数最终将被执行,对象的非堆内存将被回收。因为它不是堆内存,所以可以吗?

这取决于如何分配内存,以及这样做的机制(“运行时”或“内存管理器”)是否在特定DLL和应用程序的其他部分之间共享。例如,
抛出新的my_异常(args)也可以按顺序排列,具体取决于详细信息

您可以对异常引用进行计数,这样它就具备了如何销毁自己的实例(和拥有的内存)的内在知识

使用
IMalloc
(参见MSDN)例如分配和放置
new
将是另一种方法(之前调用
OleInitialize


实际上,内存分配是一个取决于所使用内容的问题。例如,在应用程序的不同部分混合静态链接的CRT和动态链接的CRT将导致问题,就像混合调试和发布代码一样。这里的问题是,用来释放内存的代码使用了不同的“内存管理器”。但是如果抛出的对象知道它自己的破坏,它应该是好的,因为DRTC代码将驻留在与分配它相同的编译单元中。

< P>在DLL边界上抛出C++异常只有当所有模块使用同一个C++运行时才是可能的,在这种情况下,它们也共享堆。但这可能是一个维护负担,特别是当涉及多个供应商的库时,因此不鼓励这样做


如果您希望在多个编译器/编译器版本/编译器设置之间进行可移植的错误处理,请使用返回代码或操作系统提供的异常(例如Windows上的SEH)/

您引发的异常不是您捕获的异常;沿途会制作一份副本。也就是说,我不知道副本驻留在哪里,也不知道它是如何销毁的。@马克:当引用捕获异常时,这仍然是真的吗?你有一个源吗?@:AfAIK,C++要求一个异常有一个公开的可访问复制构造函数,但是它是关于是否真的使用它来复制的一个实现。很可能是捕获的同一个对象。@Ben:从N3225开始,
15.1抛出异常
3:抛出表达式初始化临时对象…
5:异常对象的内存以未指定的方式分配…
@Paul:
5:当抛出的对象是类对象时,复制/移动构造函数和析构函数应可访问,即使复制/移动操作被省略
@Ben:From N3225,
15.3处理异常
16:异常声明中声明的对象,或者,如果异常声明未指定名称,则临时(12.2)被复制初始化(8.5)从异常对象…
17:…当处理程序声明对非常量对象的引用时,对引用对象的任何更改都是对在执行抛出表达式时初始化的临时对象的更改,如果该对象被重新调用,这些更改将生效。
,"... 在这种情况下,它们也共享一个堆。“我特别询问了不涉及堆内存的情况。@保罗:我想说的是,如果你有理由的话(有很多好的理由)不在DLL之间共享堆内存,同样的原因会阻止您在DLL之间共享异常。所以在DLL之间共享一个简单的POD结构也不好吗?如果DLL中的函数按值返回一个结构会怎么样?该临时结构最终会被破坏。同样的问题?如果不是,为什么不是?@Paul:不是异常结构造成的问题是,编译器的内部数据用于查找匹配的catch块并执行堆栈展开,所有这些都是高度特定于编译器的,可能使用全局变量,甚至可能使用堆。如果所有模块都不共享运行时,则会出现问题。为什么需要iAlloc?如果要动态分配,请参阅正如你所建议的那样,通过new计算异常对象,那么只要new/delete对是在DLL代码中完成的,为什么这还不足以解决问题呢?@Paul J.Lucas:这就是为什么它说“这是另一种方式”“在我提到IMalloc的句子中。对不起,如果不清楚的话。英语不是我的母语。我将把它移到一个单独的段落。。。
throw my_exception( args ); // temporary: no heap allocation