Of course using the class for returnin a pointer to something you created requires a bit of thinking (exactly the same amount of think for a IReferenceCounted object). But if some class returned the pointer to you you have no longer to warry about that. You can copy the pointer how many times you like and still being sure it will be released corretly ^^
Feel free to criticize, I writed it in 10 minutes without never checking if it compiles or work ^^.
file IrrAutoPtr.h
Code: Select all
#ifndef IRR_AUTOPTR_H_INCLUDED
#define IRR_AUTOPTR_H_INCLUDED
///AutoPtr class for use in pair with Irrlicht Engine's reference counted stuff.
///This file is placed in public domain.
///@author Dario Oliveri
#define DROP(x) if(x) x->drop
#define GRAB(x) if(x) x->grab
/** @brief: this class automatically drop a pointer when no longer needed and automatically grab
a pointer when needed. Drop happens in destructor or just before acquiring a new pointer.
grab happens when a new pointer is acquired. This class should be used and returned only as reference/item. Never use this class as pointer.
For accessing stuff of wrapper pointer you have only to use operator->
@usage:
-If you are returning a pointer return instead
return Ptr<PointerType>(p); //you don't have grabbed the poiner. else return PtrzPointerType>(p,false);
-if something returned the pointer to you you have just to call dinamic methods as always you done
myPtr->doSomething();
-You can store the pointer by copying this class (little example with irrlicht device)
class Foo
{
Ptr<IrrlichtDevice> p;
public:
Foo( Ptr<IrrlichtDevice>& bar)
{
p = bar;
}
void closeDevice()
{
p->closeDevice();
}
}
-of course before sending Ptr<IrrlichtDevice> to any class you need it so (unless someone else returned to you the pointer)
Ptr<IrrlichtDevice> game;
IrrlichtDevice * device = createDeviceEx(params);
game.set(device,false); //already grabbed.
Foo Name(game); //if you forget this line device will be dropped automatically at the end of the scope. Wich is wanted since you are no longer using Device.
*/
namespace irr
{
namespace core
{
template <typename T>
class Ptr
{
T * p;
public:
///initialize the container. Ready to acquire a pointer
inline Ptr():p(0)
{
}
inline Ptr( Ptr<T>& other, bool grab)
{
DROP(p);
p=other.p;
if(grab) //usefull for functions wich returns something that has already been grabbed(Ex. createDevice)
GRAB(p);
}
inline Ptr( T* other, bool grab)
{
DROP(p);
p=other;
if(grab) //usefull for functions wich returns something that has already been grabbed(Ex. createDevice)
GRAB(p);
}
inline Ptr( T* other)
{
DROP(p);
p=other;
GRAB(p);
}
inline Ptr( Ptr<T>& other)
{
DROP(p);
p=other.p;
GRAB(p);
}
inline ~Ptr()
{
DROP(p);
}
inline const T* operator->() const
{
return p;
}
inline T* operator->()
{
return p;
}
inline Ptr<T> & operator = (Ptr<T>& other)
{
DROP(p);
p = other.p;
GRAB(p);
return (*this);
}
inline Ptr<T> & operator = (T* other)
{
DROP(p);
p = other;
GRAB(p);
return (*this);
}
inline void set(Ptr<T> & other)
{
DROP(p);
p = other.p;
GRAB(p);
}
inline void set(T* other)
{
DROP(p);
p = other;
GRAB(p);
}
inline void set(Ptr<T> & other,bool grab)
{
DROP(p);
p = other.p;
if(grab)
GRAB(p);
}
inline void set(T* other,bool grab)
{
DROP(p);
p = other;
if(grab)
GRAB(p);
}
inline void clean()
{
DROP(p);
p=0;
}
inline bool operator ==(Ptr<T> & other) const
{
return p==other.p;
}
inline bool operator ==(T* other) const
{
return p==other;
}
inline bool operator !=(Ptr<T> & other) const
{
return p!=other.p;
}
inline bool operator !=(T* other) const
{
return p!=other;
}
inline bool isValid()const
{
return p!=0;
}
};
} //namespace core
} //namespace irr
#endif // IRR_AUTOPTR_H_INCLUDED
little unsolved question:
I don't know if it can works just with forwards declaration. (for example in the header of a file you can put
Ptr<IrrlichtDevice> with IrrlichtDevice forward declared
and only in the implementation files you need to include IrrlichtDevice.h. Didn't tested yet^^)