Forum Thread Not Found, Sorry.

Game Development Community

[b3 bug] SimObject::setAutoDelete() doesn't work. [w/ fix] - RESOLVED

by Manoel Neto · in Torque 3D Professional · 03/03/2011 (6:56 am) · 6 replies

In beta2 the SimObjectPtr was re-written to be nothing more than a thin shell for WeakRefPtr. I believe this was done to allow SimObjectPtrs to be stored in movable memory, since with WeakRefPtrs the reference pointer has an extra indirection layer over it.

The problem is in that the new SimObjectPtr no longer calls registerReference/unregisterReference to the referred object and thus cannot trigger the AutoDelete behavior. This causes any code that relied in setAutoDelete() to clean up temporary/dynamic SimObjects to turn into memory leaks.

I'm looking into how to fix this, since using registerReference() would bring back old bugs about SimObjectPtr and movable memory.

#1
03/03/2011 (8:48 am)
Alright, I got it "fixed". Slightly hack-ish (having to resort to "friendship"), but it works:

First we need a few extra features in engine/source/core/util/refBase.h.

Add this:
U32 getRefCount() { return mRefCount; }
Right after this block:
WeakRefBase * get() { return mObject; }
void incRefCount() { mRefCount++; }
void decRefCount()
{
   AssertFatal( mRefCount > 0, "WeakReference - decrementing count of zero!" );
   if (--mRefCount==0)
      delete this;
}

Add this:
template< typename T > class SimObjectPtr;
Right above this:
template <class T> class WeakRefPtr

Now change this block:
private:
   WeakRefBase::WeakReference * mReference;
To this:
private:
   template< typename T > friend class SimObjectPtr;
   WeakRefBase::WeakReference * mReference;

Now go to engine/source/console/simObject.h and replace this:
class SimObjectPtr : public WeakRefPtr< T >
{
   public:
   
      typedef WeakRefPtr< T > Parent;
   
      SimObjectPtr() {}
      SimObjectPtr( T* ptr )
         : Parent( ptr ) {}
      SimObjectPtr( const SimObjectPtr& ref )
         : Parent( ref ) {}
         
      T* getObject() const { return Parent::getPointer(); }
};

By this:
class SimObjectPtr : public WeakRefPtr< T >
{
   public:
   
      typedef WeakRefPtr< T > Parent;
   
      SimObjectPtr() {}
      /* // THIS CODE IS DISABLED
      SimObjectPtr( T* ptr )
         : Parent( ptr ) {}
      SimObjectPtr( const SimObjectPtr& ref )
         : Parent( ref ) {}
      */
         
      T* getObject() const { return Parent::getPointer(); }

   //---------------------------------------------
   // NEW CODE
      SimObjectPtr(T *ptr)  { mReference = NULL; set(ptr); }
      SimObjectPtr( const SimObjectPtr& ref ) { mReference = NULL; set(ref.mReference); }
      
      ~SimObjectPtr() { set((WeakRefBase::WeakReference*)NULL); }

      SimObjectPtr<T>& operator=(const SimObjectPtr ref)
      {
         set(ref.mReference);
         return *this;
      }
      SimObjectPtr<T>& operator=(T *ptr)
      {
         set(ptr);
         return *this;
      }

   protected:
   void set(WeakRefBase::WeakReference * ref)
   {
      if (mReference)
      {
         // Auto-delete
         T* obj = getPointer();
         if ( mReference->getRefCount() == 2 && 
              obj && obj->isAutoDeleted() )
              obj->deleteObject();

         mReference->decRefCount();
      }
      mReference = NULL;
      if (ref)
      {
         mReference = ref;
         mReference->incRefCount();
      }
   }
   void set(T * obj) { set(obj ? obj->getWeakReference() : (WeakRefBase::WeakReference *)NULL); }
   // END OF NEW CODE
   //---------------------------------------------
};
#2
03/03/2011 (5:21 pm)
Compiles fine Manoel, though I don't yet have the coding mad skillz to verify the fix. ;)
#3
03/03/2011 (11:29 pm)
Hi Manoel, I remember we discussed the matter in history. I have a question to your code, you checked on line 42 for refCount == 2.
One is the current current reference, ok, the second, for the global group reference?

For me it´s not clear at the moment, if the SFX Resource is released, when erased from the mPlayOnceSources vector, because I haven't found any template specialisation for our smart pointers. Propably I'm wrong, so I will check it.

Included your code already and will conduct a smart test.
#4
03/04/2011 (10:58 am)
Quote:Hi Manoel, I remember we discussed the matter in history. I have a question to your code, you checked on line 42 for refCount == 2.
One is the current current reference, ok, the second, for the global group reference?
A refCount == 1 means no external references to the object exist. Since these are weak references, the object contains an internal reference to itself. I could check for refCount == 1 after decRefCount(), but that would be unsafe since the internal reference pointer might have been deleted already.

So a refCount == 2 right before a decRefCount() means this the last external reference is being removed.
#5
03/15/2011 (3:45 pm)
Greetings!

Logged as THREED-1465. Thanks!

- Dave
#6
04/18/2011 (4:12 pm)
Fixed in 1.1 Final and Preview.