Deallocation of DLL-allocated objects

Started by
16 comments, last by Jansic 16 years, 11 months ago
Quote: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.

I'm fairly certain this is incorrect since forced calls to destructors "object->~object()" don't result in memory being freed. In fact the whole point of the original question was to prevent the memory manager of one module going looking for an object pointer from another module, if this mechanism worked then we'd never need to bother.

Jans.
Advertisement
BTW, what sort of an environment are you expecting to use this in? If you're planning to use this interface between different compilers, none of this will work because of ABI incompatibilities. And if you're doing it all on one compiler, as long as you use a DLL-compatible runtime (as is default for recent visual studio versions) there's nothing to worry about at all and you don't need special deletion functions.
Now I'm getting a bit confused here. Let me make myself clear :

CORE - Static Library, constains the base "Unknown" class.
FOOBAR - Dynamic library, links to CORE and derives it's classes from CORE'S "Unknown" class.
GAME - Application, links to CORE and uses FOOBAR.

Now, if the "delete this;" are inlined into CORE, when FOOBAR will compile, the "delete this;" code will be pasted into the FOOBAR dll. As such, it will be the foobar itself deleting it's own allocated memory, and that'd work...

No.

Writing this I saw the problem : even if FOOBAR can deallocate it's own memory correctly, the GAME linking to CORE will inline the "delete this;" and delete the FOOBAR objects as if it was in the GAME's memory thing.

So I need to use pure virtuals.
The easiest solution to this is to make your base class pure and force the reference counting in at instantiation time, like this:

// Pure baseclass Unknown{public:    virtual void grab()=0;    virtual void drop()=0;};// Your classclass MyClass : Unknown{    // MyClass stuff, but do not implement Unknown};// Instantiation wrappertemplate <typename BASE>class Dynamic : public BASE{    int m_iRefCount;public:    Dynamic() { m_iRefCount = 0; }    void grab() { m_iRefCount++; }    void drop() { if ( --m_iRefCount == 0 ) delete this; }};

So... in the DLL that _provides_ these objects you can instantiate the object as follows:

MyClass *CreateMyClass()  // Example only - returning refcounted objects like this is bad form.{    MyClass *pMyClass = new Dynamic<MyClass>();    pMyClass->grab();    return pMyClass;  }

This has the hidden benefit that if MyClass multiply inherits 'unknown' through two different paths, it all still works...

Jans.
No, it would not work if you inherit from Unknown from different parents, the call will be ambiguous.

EDIT: Unless you use virtual inheritance for Unknown obviously :-)
This is what I use for most of classes (apart from very simple one's):
// .h fileclass MyClass{public:   static MyClass* create();   void release();protected:// Make sure that the only way to create and destroy the object is by using the create/release pair.   MyClass();   ~MyClass();};// .cpp fileMyClass*MyClass::create(){   return new MyClass;}voidMyClass::release(){   delete this;}


This makes sure that the object can only be alloacted and deallocated within the same compilation unit.
Done it in this way for years now (very often using DLL's) without any problems.

If you want to add ref counting, com style intefaces on top of that, it's up to you.
But to make sure that a class can be used with DLL's the above seems to be enough.
What about this :

// Unknown.hppclass Unknown{private:  int m_RefCount;  inline Unknown() : m_RefCount(0) {} // Private constructor  virtual ~Unknown() {} // Private destructorprotected:  virtual selfDestroy() = 0;public:  inline void grab() { ++m_RefCount; }  inline void drop() { if(--m_RefCount <= 0) selfDestroy(); }  inline int getRefCount() const { return m_RefCount; }  template<class> friend class UnknownBase; // Whatever the syntax for this is};template<class T>class UnknownBase : virtual public Unknown{protected:  inline UnknownBase() {} // Protected constructor  virtual ~UnknownBase() {} // Protected destructorpublic:  static T * Create();};


And then :

// Derived.hppclass Derived : public UnknownBase<Derived>{protected:  virtual void selfDestroy();};// Derived.cppDerived * UnknownBase<Derived>::Create() { return new Derived(); }void Derived::selfDestroy() { delete this; }


This solves the problems of :
- Mandatory allocation via a common static function (must derive from UnknownBase because Unknown's constructor is private)
- Deallocation via a virtual function
- Reference counting in base class
- Mandatory virtual inheritance from Unknown because of mandatory inheritance from UnknownBase

Is there any problem with this approach?

[Edited by - Trillian on May 12, 2007 7:04:26 AM]
Quote:Original post by ldeej
No, it would not work if you inherit from Unknown from different parents, the call will be ambiguous.

EDIT: Unless you use virtual inheritance for Unknown obviously :-)

I was taking the requirement for virtual inheritance as read.

Jans.

This topic is closed to new replies.

Advertisement