Wrapping a C lib and reference counting

M

Mosfet

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 ?
 
M

Maxim Yegorushkin

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
 
M

Michael Doubez

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.
 
M

Mosfet

Michael Doubez a écrit :
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 :)


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

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top