AutoPtr

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

AutoPtr

Post by REDDemon »

Since many users are complaining about the Reference Count of Irrlicht i thinked that would be nice a AutoPtr. What it does is very simple. It automatically grab/drop stuff when needed (except if it has already grabbed for example with createDevice, in that case you can specify to don't grab on acquisition).
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^^)
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: AutoPtr

Post by REDDemon »

I had problems editing the above post so I deleted it and writed again. I had white window. Maybe caused by

Code: Select all

"<" and ">"
of lines using templates


This class still don't avoid memory leaks!. If you continue to copy over a Ptr<ofsomething> it will increase its reference count without being deleted. When 2 objects are grabbing each one the other is another case in wich they will never being deleted. So the AutoPtr doesn't solve all the troubles. Just few troubles. (and can create other troubles of course XD)
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: AutoPtr

Post by hybrid »

boost and c++11 have autoptr concepts which should be more mature probably.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: AutoPtr

Post by REDDemon »

how many irrlicht users are going to use use boost? :) anyway. most of opensource solution i found use "release" instead of "drop" so unless someone change the code they will not work with irrlicht stuff O_O. anyway yes. the posted class is very simple so also easy to use and understand. In some case can be better something simple that something full featured... XD
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: AutoPtr

Post by CuteAlien »

Hm, same bugs as last guy implementing it, assigning self-reference will kill your object. You should generally avoid calling drop before grab in such situations (we had made that error a few times in Irrlicht as well in the past, but should be all fixed by now). Here's the last guy posting an autoptr (could be there is another one somewhere with a little searching): http://irrlicht.sourceforge.net/forum/v ... =9&t=31993

I've made one implementation as well in the past, but also no guarantee it's bug-free:

Code: Select all

 
#ifndef IRR_PTR_H
#define IRR_PTR_H
 
//! Save wrapper around the the reference counted pointers with an interface like irr::IReferenceCounted
//! NOTE: IrrPtr is made to mostly look like boost::shared_ptr. Differences are mostly because it has not the exact same job.
template <typename T>
class IrrPtr
{
public:
 
    //! Default constructor for empty IrrPtr
    IrrPtr()
    : mRefCounted(0)
    {
    }
 
    //! constructor
    /** \param ptr A reference counted pointer
        \param grab When true the reference count for the pointer is increased.
                    When false it is expected that the ptr has already an increased reference counter, for example because
                    it was returned by one of the Irrlicht create functions */
    explicit IrrPtr(T * ptr, bool grab=true)
    : mRefCounted(ptr)
    {
        if ( mRefCounted && grab )
            mRefCounted->grab();
    }
 
    //! copy constructor
    IrrPtr(const IrrPtr& other)
    : mRefCounted(0)
    {
        *this = other;
    }
 
    //! destructor
    ~IrrPtr()
    {
        if ( mRefCounted )
            mRefCounted->drop();
    }
 
    //! assign operator
    IrrPtr& operator=(const IrrPtr& other)
    {
        if ( this == &other )   // currently not needed due to set implementation, I just feel bad removing it.
            return *this;
 
        set(other.mRefCounted);
 
        return *this;
    }
 
    //! Dereference can use the managed pointer directly
    T & operator*() const
    {
        return *mRefCounted;
    }
 
    //! Memberaccess can use the managed pointer directly
    T * operator->() const
    {
        return mRefCounted;
    }
 
    //! Allows using bool operations for IrrPtr
    /** Like: IrrPtr<SomeType> instance; if ( instance ) { // do }; if ( !instance) { // do not } */
    typedef T * (IrrPtr::*unspecified_bool_type)() const;
    operator unspecified_bool_type () const
    {
        return mRefCounted ? &IrrPtr<T>::get : 0;
    }
 
    bool operator==(const IrrPtr<T>& other) const
    {
        return mRefCounted == other.mRefCounted;
    }
 
    bool operator!=(const IrrPtr<T>& other) const
    {
        return mRefCounted != other.mRefCounted;
    }
 
    bool operator<(const IrrPtr<T>& other) const
    {
        return mRefCounted < other.mRefCounted;
    }
 
    //! Access pointer directly
    T * get() const
    {
        return mRefCounted;
    }
 
    //! set a new pointer.
    /** The old pointer will be released unless it's identical with the new one.
        If old and new pointer are identical then nothing is done.
        \param ptr A reference counted pointer
        \param grab When true the reference count for the pointer is increased.
                    When false it is expected that the ptr has already an increased reference counter, for example because
                    it was returned by one of the Irrlicht create functions */
    void set(T * ptr, bool grab=true)
    {
        if ( mRefCounted != ptr )
        {
            if ( mRefCounted )
                mRefCounted->drop();
            mRefCounted = ptr;
            if ( mRefCounted )
                mRefCounted->grab();
        }
    }
 
    //! After a reset the class contains no longer a pointer.
    void reset()
    {
        if ( mRefCounted )
        {
            mRefCounted->drop();
            mRefCounted = 0;
        }
    }
 
    //! Swap the content with that of another IrrPtr
    void swap(IrrPtr<T> & other)
    {
        T * dummy = mRefCounted;
        mRefCounted = other.mRefCounted;
        other.mRefCounted = dummy;
    }
 
private:
    T * mRefCounted;
};
 
#endif // IRR_PTR_H
 
 

edit: Thinking a little about it... I guess it would be possible to avoid creating a new class-instance for every pointer-type, I remember reading some article once about how to code templates with pointers in a way that prevents that (I did read that after I wrote this class, so I didn't think of it back then).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Re: AutoPtr

Post by serengeor »

REDDemon wrote:how many irrlicht users are going to use use boost? :)
What is the problem with using boost? It's big, but It has some really useful code and you can probably get away by just extracting the things you need from there.
And as hybrid said, autoptr should be in the coming standard.
Working on game: Marrbles (Currently stopped).
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: AutoPtr

Post by CuteAlien »

No idea really at which point we can switch to using c++11 features in Irrlicht. Probably depends on the feature (for example next VS will add better c++11 support, but on the cost of dropping support for Windows XP).

Boost... I'm using it in one project, but will probably use it _less_ in the next project I start from scratch as my original enthusiasm for it started dropping a lot after working with it for a year. But certainly stuff like shared_ptr is useful, although the ugly casting-syntax for the autopointers makes your code look like someone has pushed it through the meat grinder.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: AutoPtr

Post by REDDemon »

CuteAlien wrote: You should generally avoid calling drop before grab
yeah I see. if the two pointers are pointing to the same object it can be deleted

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)
        {
            if(grab)  //usefull for functions wich returns something that has already been grabbed(Ex. createDevice)
                GRAB(other.p);
            DROP(p);
            p=other.p;
           
        }
 
        inline Ptr( T* other, bool grab)
        {
            if(grab)  //usefull for functions wich returns something that has already been grabbed(Ex. createDevice)
                GRAB(other.p);
            DROP(p);
            p=other;
        }
 
        inline Ptr( T* other)
        {
            GRAB(other.p);
            DROP(p);
            p=other;
        }
 
        inline Ptr( Ptr<T>& other)
        {
            GRAB(other.p);
            DROP(p);
            p=other.p;
        }
 
        inline ~Ptr()
        {
            DROP(p);
        }
 
        inline const T* operator->() const
        {
            return p;
        }
 
        inline T* operator->()
        {
            return p;
        }
 
        inline Ptr<T> & operator = (Ptr<T>& other)
        {
            GRAB(other.p);
            DROP(p);
            p = other.p;
            return (*this);
        }
 
        inline Ptr<T> & operator = (T* other)
        {
            GRAB(other.p);
            DROP(p);
            p = other;
            return (*this);
        }
 
        inline void set(Ptr<T> & other)
        {
            GRAB(other.p);
            DROP(p);
            p = other.p;
        }
 
        inline void set(T* other)
        {
            GRAB(other.p);
            DROP(p);
            p = other;
        }
 
        inline void set(Ptr<T> & other,bool grab)
        {
            if(grab)
                GRAB(other.p);
            DROP(p);
            p = other.p;
        }
 
        inline void set(T* other,bool grab)
        {
            if(grab)
                GRAB(other.p);
            DROP(p);
            p = other;
        }
 
        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
 
 
 
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: AutoPtr

Post by CuteAlien »

I would avoid the defines. You could use some inline-functions if you really want to avoid typing those few if check's. The problem with define is that they pollute the global namespace, so it's just safer avoiding them unless you find really no way around them.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Ethon
Posts: 21
Joined: Wed Nov 30, 2011 10:01 am

Re: AutoPtr

Post by Ethon »

1. I miss move semantics.
2. Using macros as a replacement for functions is a bad idea.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: AutoPtr

Post by REDDemon »

this is a obscure point. there are several very good books suggestin exactly the use of macros for speed up coding I guess there will be pros not only cons.. and also many good opensource libraries doing exactly what I did.

what you u mean by "move semantics"?

anyway the "edit" button for the main post don't work. I can't update it.


anyway I agree. If I can replace the macro with a template should be perfect. no namespace pollution and more reusability. what I find interesting is using templates for removing the cost of the "grab/drop" calls. I'm trying to find good articles about that.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: AutoPtr

Post by hybrid »

No, macros should never be used as a replacement for functions. Just for certain compile time options, which should be configurable by the user.
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: AutoPtr

Post by teto »

With C++11 you can use the keyword "constexpr" to run functions at compile time. But still, in some cases macros are needed, if you don't want them to pollute global space, add an #undef at the end of the file
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: AutoPtr

Post by REDDemon »

I think that I'll continue to use macros until they help to keep code clear and maintenable. Of course I will not abuse of them. :D.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Re: AutoPtr

Post by randomMesh »

REDDemon wrote:I'll continue to use macros until they help to keep code clear and maintenable.
No. Clean and maintainable C++ code doesn't use any macros.
Please do yourself a favour and read the C++ FAQ. Macros are evil

And like others said, don't reinvent the wheel. auto_ptr is already available.

Oh, and
I writed it in 10 minutes without never checking if it compiles or work.
Posting complex code without checking if it works is a bad idea, if you want to be taken seriously.
"Whoops..."
Post Reply