Wrapping a C lib and reference counting

Discussion in 'C++' started by Mosfet, May 28, 2009.

  1. Mosfet

    Mosfet Guest

    Hi,

    I would like to wrapp a C library I wrote used to access address book on
    windows mobile and basically here is how it is designed :

    typedef void GDAddrBook;
    typedef void GDAbItem;


    GYNOID_API ErrorCode
    GDAddrBook_Open(OsHandle osParam, GDAddrBook** gppAddrbook);

    GYNOID_API ErrorCode
    GDAddrBook_Close(GDAddrBook* gpAddrbook);

    GYNOID_API ErrorCode
    GDAddrBook_GetCount(GDAddrBook* gpAddrbook, int* ulCount);

    GYNOID_API ErrorCode
    GDAbItem_Release(GDAbItem* gpContact);

    GYNOID_API ErrorCode
    GDAddrBook_GetItem(GDAddrBook* gpAddrbook, int iIndex, GDAbItem**
    gppAbItem);

    GYNOID_API void*
    GDAbItem_GetProperty(GDAbItem* gpContact, EAbItemProp eContactProp);


    So A typical use to get the first addrbook item would be (simple case
    with no error checking):

    GDCTSTR lpFirstName;
    GDAddrBook* gdAb;
    GDAbItem* gdAbItem;

    GDAddrBook_Open(0, &gdAb);
    GDAddrBook_GetItem(gdAb, 0, &gdAbItem);

    lpFirstName = (GDCTSTR) GDAbItem_GetProperty(gdAbItem, eAbFirstName);

    // Now we release our two "objects"
    GDAbItem_Release(gdAbItem);
    GDAddrBook_Release(gdAb)


    Now I would like to provide a C++ wrapper where C++ objects would hold
    GDxxxx pointers and would call Gdxxxx_Release automatically

    AddrBook ab;
    AddrBookItem abItem;

    abItem = ab.getItem(0);
    GDString = abItem.getProperty(eAbFirstName);

    The problem is about

    AddrBookItem AddrBook::getItem(int iIndex)
    {
    GDAbItem* gpAbItem = NULL;
    GDAddrBook_GetItem(m_gpAb, iIndex, &gpAbItem);
    AddrBookItem abItem(gpAbItem);

    return abItem;
    }


    Because If I write something like that, my local abItem will be
    destroyed and will call its destructor, so my internal pointer will be
    released.
    The only way I can see is to use reference counting but is it the only way ?

    Another approach would be to use reference like that :

    ab.getItem(0, abItem );

    but what is the best way and how to solve my issues ?
    Mosfet, May 28, 2009
    #1
    1. Advertising

  2. On May 28, 2:00 pm, Mosfet <> wrote:
    > Hi,
    >
    > I would like to wrapp a C library I wrote used to access address book on
    > windows mobile and basically here is how it is designed :
    >
    > typedef void GDAddrBook;
    > typedef void GDAbItem;


    These seem to be rather long new names for void with little utility.

    Probably, you want to add some type safety to justify your long names:

    typedef struct GDAddrBookTag* GDAddrBook;
    typedef struct GDAbItemTag* GDAbItem;

    This way you can't use GDAddrBook in place of GDAbItem and vice versa.

    > GYNOID_API ErrorCode    
    > GDAddrBook_Open(OsHandle osParam, GDAddrBook** gppAddrbook);
    >
    > GYNOID_API ErrorCode    
    > GDAddrBook_Close(GDAddrBook* gpAddrbook);
    >
    > GYNOID_API ErrorCode    
    > GDAddrBook_GetCount(GDAddrBook* gpAddrbook, int* ulCount);
    >
    > GYNOID_API ErrorCode    
    > GDAbItem_Release(GDAbItem* gpContact);
    >
    > GYNOID_API ErrorCode    
    > GDAddrBook_GetItem(GDAddrBook* gpAddrbook, int iIndex, GDAbItem**
    > gppAbItem);
    >
    > GYNOID_API void*                
    > GDAbItem_GetProperty(GDAbItem* gpContact, EAbItemProp eContactProp);
    >
    > So A typical use to get the first addrbook item would be (simple case
    > with no error checking):
    >
    > GDCTSTR lpFirstName;
    > GDAddrBook* gdAb;
    > GDAbItem* gdAbItem;
    >
    > GDAddrBook_Open(0, &gdAb);
    > GDAddrBook_GetItem(gdAb, 0, &gdAbItem);
    >
    > lpFirstName = (GDCTSTR) GDAbItem_GetProperty(gdAbItem, eAbFirstName);
    >
    > // Now we release our two "objects"
    > GDAbItem_Release(gdAbItem);
    > GDAddrBook_Release(gdAb)
    >
    > Now I would like to provide a C++ wrapper where C++ objects would hold
    > GDxxxx pointers and would call Gdxxxx_Release automatically
    >
    > AddrBook ab;
    > AddrBookItem abItem;
    >
    > abItem = ab.getItem(0);
    > GDString = abItem.getProperty(eAbFirstName);
    >
    > The problem is about
    >
    > AddrBookItem AddrBook::getItem(int iIndex)
    > {
    >       GDAbItem* gpAbItem = NULL;
    >       GDAddrBook_GetItem(m_gpAb, iIndex, &gpAbItem);
    >       AddrBookItem abItem(gpAbItem);
    >
    >       return abItem;
    > }
    >
    > Because If I write something like that, my local abItem will be
    > destroyed and will call its destructor, so my internal pointer will be
    > released.
    > The only way I can see is to use reference counting but is it the only way ?


    Reference counting is the easiest here.

    Another way is to be as fancy as std::auto_ptr<> is. I.e. transfer the
    ownership of the handle on copy construction and assignment. The
    downside is that such fancy objects can not be stored in containers
    and one has to be extra careful to avoid accidental copying.

    In C++0x you would solve this elegantly by using move constructors.
    http://en.wikipedia.org/wiki/C++0x#Rvalue_reference_and_move_semantics

    --
    Max
    Maxim Yegorushkin, May 28, 2009
    #2
    1. Advertising

  3. On May 28, 3:00 pm, Mosfet <> wrote:
    > Hi,
    >
    > I would like to wrapp a C library I wrote used to access address book on
    > windows mobile and basically here is how it is designed :
    >
    > typedef void GDAddrBook;
    > typedef void GDAbItem;
    >
    > GYNOID_API ErrorCode    
    > GDAddrBook_Open(OsHandle osParam, GDAddrBook** gppAddrbook);
    >
    > GYNOID_API ErrorCode    
    > GDAddrBook_Close(GDAddrBook* gpAddrbook);
    >
    > GYNOID_API ErrorCode    
    > GDAddrBook_GetCount(GDAddrBook* gpAddrbook, int* ulCount);
    >
    > GYNOID_API ErrorCode    
    > GDAbItem_Release(GDAbItem* gpContact);
    >
    > GYNOID_API ErrorCode    
    > GDAddrBook_GetItem(GDAddrBook* gpAddrbook, int iIndex, GDAbItem**
    > gppAbItem);
    >
    > GYNOID_API void*                
    > GDAbItem_GetProperty(GDAbItem* gpContact, EAbItemProp eContactProp);
    >
    > So A typical use to get the first addrbook item would be (simple case
    > with no error checking):
    >
    > GDCTSTR lpFirstName;
    > GDAddrBook* gdAb;
    > GDAbItem* gdAbItem;
    >
    > GDAddrBook_Open(0, &gdAb);
    > GDAddrBook_GetItem(gdAb, 0, &gdAbItem);
    >
    > lpFirstName = (GDCTSTR) GDAbItem_GetProperty(gdAbItem, eAbFirstName);
    >
    > // Now we release our two "objects"
    > GDAbItem_Release(gdAbItem);
    > GDAddrBook_Release(gdAb)
    >
    > Now I would like to provide a C++ wrapper where C++ objects would hold
    > GDxxxx pointers and would call Gdxxxx_Release automatically
    >
    > AddrBook ab;
    > AddrBookItem abItem;
    >
    > abItem = ab.getItem(0);
    > GDString = abItem.getProperty(eAbFirstName);
    >
    > The problem is about
    >
    > AddrBookItem AddrBook::getItem(int iIndex)
    > {
    >       GDAbItem* gpAbItem = NULL;
    >       GDAddrBook_GetItem(m_gpAb, iIndex, &gpAbItem);
    >       AddrBookItem abItem(gpAbItem);
    >
    >       return abItem;
    >
    > }
    >
    > Because If I write something like that, my local abItem will be
    > destroyed and will call its destructor, so my internal pointer will be
    > released.
    > The only way I can see is to use reference counting but is it the only way ?


    You could also duplicate it at each copy.

    For your function, you can also create an artefact AddrBookItemRef
    that destroy its ressource if it was not used by a AddrBookItem.

    class AddrBookItem
    {
    //...
    class AddrBookItemRef
    {
    public:
    AddrBookItemRef(GDAbItem*p=NULL):ptr(p){}
    AddrBookItemRef(const AddrBookItemRef& r):ptr(p.release()){}
    ~AddrBookItemRef(){if(ptr)GDAbItem_Release(ptr);}
    private:
    GDAbItem* release()const{GDAbItem*p=ptr;ptr=NULL;return p;}
    mutable GDAbItem* ptr;
    };

    AddrBookItem(const AddrBookItemRef& r)
    {
    internal=r.release();
    }
    //...
    };

    You would have to decide what to do with copy operator for
    AddrBookItemRef (I would say forbid it).
    If you want to allow it, you can directly return a
    std::auto_ptr<GDAbItem>.

    You could also use garbage collection :)

    > Another approach would be to use reference like that :
    >
    >   ab.getItem(0, abItem );
    >
    > but what is the best way and how to solve my issues ?


    Duplicating your data doesn't seem a big deal unless you can find
    another persistence root.

    --
    Michael
    Michael Doubez, May 28, 2009
    #3
  4. Mosfet

    Mosfet Guest

    Michael Doubez a écrit :
    > On May 28, 3:00 pm, Mosfet <> wrote:
    >> Hi,
    >>
    >> I would like to wrapp a C library I wrote used to access address book on
    >> windows mobile and basically here is how it is designed :
    >>
    >> typedef void GDAddrBook;
    >> typedef void GDAbItem;
    >>
    >> GYNOID_API ErrorCode
    >> GDAddrBook_Open(OsHandle osParam, GDAddrBook** gppAddrbook);
    >>
    >> GYNOID_API ErrorCode
    >> GDAddrBook_Close(GDAddrBook* gpAddrbook);
    >>
    >> GYNOID_API ErrorCode
    >> GDAddrBook_GetCount(GDAddrBook* gpAddrbook, int* ulCount);
    >>
    >> GYNOID_API ErrorCode
    >> GDAbItem_Release(GDAbItem* gpContact);
    >>
    >> GYNOID_API ErrorCode
    >> GDAddrBook_GetItem(GDAddrBook* gpAddrbook, int iIndex, GDAbItem**
    >> gppAbItem);
    >>
    >> GYNOID_API void*
    >> GDAbItem_GetProperty(GDAbItem* gpContact, EAbItemProp eContactProp);
    >>
    >> So A typical use to get the first addrbook item would be (simple case
    >> with no error checking):
    >>
    >> GDCTSTR lpFirstName;
    >> GDAddrBook* gdAb;
    >> GDAbItem* gdAbItem;
    >>
    >> GDAddrBook_Open(0, &gdAb);
    >> GDAddrBook_GetItem(gdAb, 0, &gdAbItem);
    >>
    >> lpFirstName = (GDCTSTR) GDAbItem_GetProperty(gdAbItem, eAbFirstName);
    >>
    >> // Now we release our two "objects"
    >> GDAbItem_Release(gdAbItem);
    >> GDAddrBook_Release(gdAb)
    >>
    >> Now I would like to provide a C++ wrapper where C++ objects would hold
    >> GDxxxx pointers and would call Gdxxxx_Release automatically
    >>
    >> AddrBook ab;
    >> AddrBookItem abItem;
    >>
    >> abItem = ab.getItem(0);
    >> GDString = abItem.getProperty(eAbFirstName);
    >>
    >> The problem is about
    >>
    >> AddrBookItem AddrBook::getItem(int iIndex)
    >> {
    >> GDAbItem* gpAbItem = NULL;
    >> GDAddrBook_GetItem(m_gpAb, iIndex, &gpAbItem);
    >> AddrBookItem abItem(gpAbItem);
    >>
    >> return abItem;
    >>
    >> }
    >>
    >> Because If I write something like that, my local abItem will be
    >> destroyed and will call its destructor, so my internal pointer will be
    >> released.
    >> The only way I can see is to use reference counting but is it the only way ?

    >
    > You could also duplicate it at each copy.
    >
    > For your function, you can also create an artefact AddrBookItemRef
    > that destroy its ressource if it was not used by a AddrBookItem.
    >
    > class AddrBookItem
    > {
    > //...
    > class AddrBookItemRef
    > {
    > public:
    > AddrBookItemRef(GDAbItem*p=NULL):ptr(p){}
    > AddrBookItemRef(const AddrBookItemRef& r):ptr(p.release()){}
    > ~AddrBookItemRef(){if(ptr)GDAbItem_Release(ptr);}
    > private:
    > GDAbItem* release()const{GDAbItem*p=ptr;ptr=NULL;return p;}
    > mutable GDAbItem* ptr;
    > };
    >
    > AddrBookItem(const AddrBookItemRef& r)
    > {
    > internal=r.release();
    > }
    > //...
    > };
    >
    > You would have to decide what to do with copy operator for
    > AddrBookItemRef (I would say forbid it).
    > If you want to allow it, you can directly return a
    > std::auto_ptr<GDAbItem>.
    >
    > You could also use garbage collection :)
    >
    >> Another approach would be to use reference like that :
    >>
    >> ab.getItem(0, abItem );
    >>
    >> but what is the best way and how to solve my issues ?

    >
    > Duplicating your data doesn't seem a big deal unless you can find
    > another persistence root.
    >
    > --
    > Michael


    Finally I have adopted an hybrid approach, now all my GD object are
    inheriting from GDObject;

    typedef struct _GDObject
    {
    unsigned long cRefs;
    } GDObject;


    typedef GDObject GDAddrBook;
    typedef GDObject GDAbItem;

    I have added two functions :

    unsigned long
    GDObject_AddRef(GDObject* gdObject)
    {
    return 0;
    }

    unsigned long
    GDObject_Release(GDObject* gdObject)
    {
    return 0;
    }

    and now when object is copied I increment counter.
    When it's 0 it's deallocated.
    Mosfet, May 28, 2009
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. James Yong
    Replies:
    0
    Views:
    545
    James Yong
    Sep 12, 2005
  2. Replies:
    3
    Views:
    2,749
  3. mathieu
    Replies:
    8
    Views:
    509
    Juha Nieminen
    Aug 31, 2008
  4. NAKAMURA, Hiroshi
    Replies:
    0
    Views:
    132
    NAKAMURA, Hiroshi
    Jul 6, 2004
  5. edwardfredriks

    counting up instead of counting down

    edwardfredriks, Sep 6, 2005, in forum: Javascript
    Replies:
    6
    Views:
    197
    Dr John Stockton
    Sep 7, 2005
Loading...

Share This Page