G
Grey Alien
I have an existing ANSI C library which makes extensive use of structs.
I use these structs in my C++ code, but would like to benefit from C++
features such as ctors/dtors etc. I have modified the C header, as shown
below, with inline functions, so that I can benefit from C++ features,
whilst keeping the rest of the C library intact.
One thing I had to be particularly careful of is the fact that in a lot
of the C API functions, struct assignments were made (i.e. shallow
copies). I have therefore implemented the (overloaded) assignment
operator to create 'shallow' copy by default (so this is consistent with
the C API so that a pointer to the struct could be passed to a C API
function with no adverse effect). The facility still exists for an
(explicit) deepcopy. This is is what I have come up with so far. The CPP
snippet at the end of the post shows how I intend to use it.
//Header File
#ifdef __cplusplus
extern "C"
{
#endif
struct MyStruct
{
public:
MyStruct(const size_t size)
:m_shallow_copied(false)
{
if (!fooAlloc(this, size))
throw new std::bad_alloc ;
}
MyStruct(const MyStruct& ms)
:m_shallow_copied(false)
{
//deep copy because only C++ API calls this ctor
copy(ms, true);
}
MyStruct& operator= (const MyStruct& rhs)
{
//Default shallow copy on assignments
if (this != &rhs)
copy(rhs);
return *this ;
}
//explicit deepcopy
void deepcopy(const struct MyStruct* rhs)
{
copy(rhs,true);
}
~MyStruct::MyStruct
{
if (!m_shallow_copied && m_ptr)
fooFree(this);
}
//Needs to be public - for C API (too many funcs to all be friends)
void * m_ptr ;
size_t m_size ;
private:
void copy(const MyStruct& rhs, const bool deepcopy=false)
{
if (deepcopy)
{
//do we own ptr? (if so, free first)
if (m_ptr && !m_shallow_copied)
fooFree(this);
if (fooAlloc(this, rhs.size ))
throw new std::bad_alloc ;
fooCopy(this, &rhs) ;
m_shallow_copied = false ;
}
else
{
//default
m_ptr = rhs.m_ptr ;
m_size = rhs.m_size ;
m_shallow_copied = true ;
}
}
bool m_shallow_copied ;
};
/* Pure C API */
long fooAlloc(struct MyStruct* ms, const unsigned int size);
void fooFree(struct MyStruct* ms);
void fooCopy(struct MyStruct* dest, const struct MyStruct* src);
long fooJustDoIt(const struct MyStruct* ms);
#ifdef __cplusplus
};
#endif
//Sample cpp file using MyStruct (should probably use auto_ptr instead
of raw pointers ...)
#include "MyStruct.h"
class MyClass
{
public:
MyClass(const size_t s)
{ ms = new MyStruct(s); }
MyClass(const MyClass&);
~MyClass()
{delete ms ;}
long DoSomething() const
{
//pass ptr to MyStruct to C function
return fooJustDoIt(ms);
}
private:
MyStruct * ms ;
};
I would appreciate some feedback as to whether there are any subtle (or
not so subtle) caveats/gotchas I must be aware of with this approach ...
I use these structs in my C++ code, but would like to benefit from C++
features such as ctors/dtors etc. I have modified the C header, as shown
below, with inline functions, so that I can benefit from C++ features,
whilst keeping the rest of the C library intact.
One thing I had to be particularly careful of is the fact that in a lot
of the C API functions, struct assignments were made (i.e. shallow
copies). I have therefore implemented the (overloaded) assignment
operator to create 'shallow' copy by default (so this is consistent with
the C API so that a pointer to the struct could be passed to a C API
function with no adverse effect). The facility still exists for an
(explicit) deepcopy. This is is what I have come up with so far. The CPP
snippet at the end of the post shows how I intend to use it.
//Header File
#ifdef __cplusplus
extern "C"
{
#endif
struct MyStruct
{
public:
MyStruct(const size_t size)
:m_shallow_copied(false)
{
if (!fooAlloc(this, size))
throw new std::bad_alloc ;
}
MyStruct(const MyStruct& ms)
:m_shallow_copied(false)
{
//deep copy because only C++ API calls this ctor
copy(ms, true);
}
MyStruct& operator= (const MyStruct& rhs)
{
//Default shallow copy on assignments
if (this != &rhs)
copy(rhs);
return *this ;
}
//explicit deepcopy
void deepcopy(const struct MyStruct* rhs)
{
copy(rhs,true);
}
~MyStruct::MyStruct
{
if (!m_shallow_copied && m_ptr)
fooFree(this);
}
//Needs to be public - for C API (too many funcs to all be friends)
void * m_ptr ;
size_t m_size ;
private:
void copy(const MyStruct& rhs, const bool deepcopy=false)
{
if (deepcopy)
{
//do we own ptr? (if so, free first)
if (m_ptr && !m_shallow_copied)
fooFree(this);
if (fooAlloc(this, rhs.size ))
throw new std::bad_alloc ;
fooCopy(this, &rhs) ;
m_shallow_copied = false ;
}
else
{
//default
m_ptr = rhs.m_ptr ;
m_size = rhs.m_size ;
m_shallow_copied = true ;
}
}
bool m_shallow_copied ;
};
/* Pure C API */
long fooAlloc(struct MyStruct* ms, const unsigned int size);
void fooFree(struct MyStruct* ms);
void fooCopy(struct MyStruct* dest, const struct MyStruct* src);
long fooJustDoIt(const struct MyStruct* ms);
#ifdef __cplusplus
};
#endif
//Sample cpp file using MyStruct (should probably use auto_ptr instead
of raw pointers ...)
#include "MyStruct.h"
class MyClass
{
public:
MyClass(const size_t s)
{ ms = new MyStruct(s); }
MyClass(const MyClass&);
~MyClass()
{delete ms ;}
long DoSomething() const
{
//pass ptr to MyStruct to C function
return fooJustDoIt(ms);
}
private:
MyStruct * ms ;
};
I would appreciate some feedback as to whether there are any subtle (or
not so subtle) caveats/gotchas I must be aware of with this approach ...