Search code examples
c++dllexceptionraii

Throwing exception from constructor across DLL boundary


There are a few questions on throwing from constructors and throwing across DLL boundaries but I can't find one that answers this specific situation.

Two things I've read:

  1. Constructors should throw exceptions if something bad happens. This ensures that objects are not left in a zombie state, removes the need for functions to check the state of an object, and enforces RAII. All good things.

  2. We shouldn't throw across DLL boundaries. Heap memory is not shared, and bad things can happen. The details of this escape me a bit, but general advice everywhere is not to do it, and so I wont. The exception (!) here, is when all code is compiled with the same compiler, but even that seems to be compiler specific and so not reliable. Error codes it is!

Now my question:

How do I safely create an instance of a class which is defined somewhere in a DLL?

I think that maybe the only safe way to do this is to make all (Exported) constructors in the DLL promise not to throw exceptions, or perhaps to provide exported free functions which return a pointer to an object which could be NULL if an exception was caught.

Can anyone suggest anything more suitable, or tell me I've got the wrong end of the stick?


Solution

  • I think your approach is the right one. Let's export factories for objects instead of objects itself.

    Btw it could be projected so that for each of your DLLs you could have an export function with the same name. So that within that export function you could have if-else block that enumerates through all the factories of the DLL and tries to construct the requested object. (Let's say, the objects are identified by name, crc32 of name, hash of name etc)

    I think it could be several approaches here. For example, instead of the common exported function you could register each of the DLL's factories on the common object on DLLMain/Attach event or handle a custom DLLMain event - your own - so that you could put the Neo object address as a param to DLLMain and register the exact factory on it for each DLL.

    But the common thing is to use factories when your object could throw an expection on ctor/init method.