Deallocation of DLL-allocated objects

Started by
16 comments, last by Jansic 16 years, 11 months ago
Hello! I have a pretty simple question. You know these IUnknown base interfaces used by DirectX (all COM?), IrrLicht and many libraries? I know those are used to ensure that deallocation of the object is done in proper memory space (and ref counting also). But I have a question regarding the implementation : My engine consists of a couple of .libs which might eventually be compiled into .dlls. Thus, I have created a base "Unknown" class which is defined in my "core" library (statically-linked). I want to know where must the "delete this;" code must be placed in order to respect the correct memory space stuff. 1- It could be inlined into the header of Unknown::selfDestroy(), but I don't think this is okay. 2- It could be defined in the .cpp implementation of Unknown::selfDestroy(), but then is the code deleting from the app or the dll? (unknown.cpp is in a statically linked library but derived classes might be in dlls) 3- It could be implemented into each and every of the Unknown-derived classes .cpp files. So, where must this be placed? Also, I'd like to know if linux's Shared Objects share the same rules.
Advertisement
The internal mechanics of COM are fairly complex, hard to explain on a single post.

I had not looked at it for a while (there is a good book that explains it fairly well, I believe is Inside COM), but you certainly want the implementation on the .cpp, you do not want it inlined unless you use a secondary memory management layer for it (not just new/delete)

Note that the COM system allocates the memory for you (CoCreateInstance), and it also releases it. You need to provide this on your Unknown code base to make sure that destruction works as expected.
I do not want to use COM, but to create a similar Unknown base class to use in my engine.

I just thought about that, it should be okay if the statically-linked core library contains the implementation (the "delete this;"), because anyways the dlls will link to this library, so the code of the core library will be integrated into the dll, thus the dlls will be calling the "delete this" into their own memory space, and it will work correctly... does that make any sense?
I don't think you entirely understand the reason for not calling delete from the app. Both the app and the DLL run in the _same_ memory space. However, they may use different systems for heap allocation. Because of this, it's important that if a piece of memory is heap-allocated with the DLL's allocation function it needs to be deallocated with the DLL's deallocation function, and vice versa if it was allocated with the app's allocation function. The COM approach, and the one you're using, is to have all of that be DLL-side. In order for this to happen, you just need to make sure that any new and delete calls on library objects are happening in a .cpp file which was compiled with the library.

EDIT: actually, after rereading your last message I have no idea whether you already knew that. Sooo... HTH. [grin]
I understand that you do not want to use COM, my point is that to achieve this behavior COM has to go through lots of tedious details, and that the book I suggested explains COM on the first few chapters from the point of view of what you are trying to do.

What you describe makes sense as long as dll boundaries are not crossed, you do not want to call delete on the wrong memory manager.

Here is the problem that I think could be found with your approach:

unknown.lib (your unknown static lib)

my_physics_dll uses unknown and exposes physics : unknown
my_graphics_dll uses unknown and exposes graphics : unknown

If you create an object on my_physics_dll (Create/AddRef) and delete it (Release) on my_graphics.dll by casting it to unknown you can end up calling the wrong memory manager (unless unknown is pure abstract)

Note also that as long as IUnknown is a pure abstract class then you should be fine since you are exposing only the interface and not the implementation.

Does it make sense?
Quote:Original post by ldeejDoes it make sense?


It does. That was clear, it answers my question. I will make Unknown pure virtual.... here, I'll toss a random implementation:

class Unknown{private:  unsigned int m_RefCount;protected:  virtual ~Unknown() {}  virtual void selfDestroy() = 0; // Implementation { delete this; } in derived classes.public:  inline Unknown() : m_RefCount(0) {}  inline void grab() { ++m_RefCount; }  inline void drop() { if(--m_RefCount == 0) selfDestroy(); }  inline unsigned int getRefCount() const { return m_RefCount; }};


Is this implementation okay? Is it ready to be used for my dll stuff?

Thanks
There's no reason to make selfDestroy virtual, as long as the destructor is virtual.
Quote:Original post by Sneftel
There's no reason to make selfDestroy virtual, as long as the destructor is virtual.


Thanks. I'll fix that. I'll inline it like the other functions.
SelfDestroy needs to be virtual to make sure the destruction respects memory allocations across dll boundaries.

This is only half the equation and this is the easy part, the hard part is allocating objects. What do you have in mind for that.
Quote:Original post by ldeej
SelfDestroy needs to be virtual to make sure the destruction respects memory allocations across dll boundaries.

Ohh, I see. You're putting the base class and the derived class in different DLLs. In that case you're right about the virtual (though if it were me, I'd put the allocation and deallocation both in the Unknown class, via a custom allocation function).

Actually... hmm. I don't think it would need to be virtual even then, since the compiler pastes the memory deallocation onto the destructor code rather than at the callsite of the destructor.

This topic is closed to new replies.

Advertisement