36

I've read various things about how one should not allocate heap memory in one DLL and deallocate it from outside that DLL. But what about throwing an exception object that is a just a temporary (as most exception objects are)? E.g.:

throw my_exception( args ); // temporary: no heap allocation 

When the exception object is caught outside the DLL, the destructor for that object will eventually be executed and the non-heap memory for the object will be reclaimed. Is that OK since it's not heap memory?

7
  • The exception you throw is not the exception you catch; a copy is made along the way. That said, I do not know where the copy resides or how its destroyed. Commented Feb 24, 2011 at 17:10
  • @Mark: Is that still true when the exception is caught by reference? Do you have a source? Commented Feb 24, 2011 at 17:18
  • @Mark: AFAIK, C++ requires that an exception have a publicly accessibly copy constructor, but it's up to an implementation as to whether to actually use it to make copies. It may very well be the same object that's caught. Commented Feb 24, 2011 at 17:26
  • 1
    @Ben: From N3225, 15.1 Throwing an exception, 3: A throw-expression initializes a temporary object..., 5: The memory for the exception object is allocated in an unspecified way... @Paul: 5: When the thrown object is a class object, the copy/move constructor and the destructor shall be accessible, even if the copy/move operation is elided Commented Feb 24, 2011 at 17:50
  • 1
    @Ben: From N3225, 15.3 Handling an exception 16: The object declared in an exception-declaration or, if the exception-declaration does not specify a name, a temporary (12.2) is copy-initialized (8.5) from the exception object... 17: ...When the handler declares a reference to a non-constant object, any changes to the referenced object are changes to the temporary object initialized when the throw-expression was executed and will have effect should that object be rethrown. Commented Feb 24, 2011 at 17:54

2 Answers 2

33

Throwing C++ exceptions across DLL boundaries is only possible when all modules use the same C++ runtime, in which case they share a heap as well. But this can be a maintenance burden, especially when libraries from multiple vendors are involved, so it is discouraged.

If you want error-handling which is portable across multiple compilers/compiler versions/compiler settings, either use return codes or OS-provided exceptions (e.g. SEH on Windows)/

Sign up to request clarification or add additional context in comments.

4 Comments

You wrote, "... in which case they share a heap as well." I specifically asked about the case where no heap memory is involved.
@Paul: What I'm saying is that if you have a reason (and there are good ones that appear a lot) not to share heap memory across DLLs, that same reason will prevent you from sharing exceptions across DLLs.
So is it also not OK to share a simple POD struct across DLLs? What if a function in a DLL returns a struct by value? That temporary will get destroyed eventually. Same problem? If not, why not?
@Paul: It's not the exception struct that's the problem, it's the compiler's internal data used to find the matching catch block and perform stack unwinding, all of which are highly compiler-specific and may use global variables, may even use the heap. If all modules aren't sharing a runtime you have problems.
1

It depends how that memory was allocated and whether the mechanism to do so ("the runtime" or "memory manager") is shared between the specific DLL and the other parts of the application. E.g. a throw new my_exception( args ); could also be in order depending on the details.

You could make your exception reference counted, so that it comes with the intrinsic knowledge of how to destroy its own instance (and owned memory).

Using IMalloc (see MSDN) for instance allocation and placement new would be another way (call OleInitialize before) ...

Indeed, the memory allocation is an issue depending on what is being used. For example mixing statically linked CRT and dynamically linked CRT in different parts of an application will lead to issues the same way the mixing debug and release code would. The problem here is that the code that is supposed to free the memory uses a different "memory manager". But if the thrown object knows about its own destruction, it should be fine, since the dtor code would reside in the same compilation unit as the one allocating it.

2 Comments

Why would IMalloc be needed? If one were to throw dynamically allocated, reference-counted exception objects via new as you suggest, then as long as the new/delete pair were done within the DLL code, why wouldn't that be sufficient to work without issue?
@Paul J. Lucas: That's why it says "would be another way" in the sentence where I mention IMalloc. Sorry if that was unclear. English is not my native language. I'll move it to a separate paragraph ...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.