Alexis King
Alexis King

Reputation: 43862

Using shared_ptr in C interfaces?

I have a C library that I'm porting to C++ that makes heavy use of manually reference-counted structs. I've considered using shared_ptr to automatically handle the reference counting, but I also want to maintain the C API. The old signatures look something like this:

Object* object_create(void);
Object* object_retain(Object* o);
void object_release(Object* o);

If I use shared_ptr, is there any way to effectively expose this manual reference counting in a C API?

Upvotes: 8

Views: 4538

Answers (3)

Calmarius
Calmarius

Reputation: 19441

Since there is no RAII in C you will need to manage the shared pointers yourself via the create/destroy functions. So the handles you return should be shared_ptr-s, and your API would look like this:

// Opaque pointer wrapped in structure for type safety (in header)
typedef struct 
{
    void *ptr;
} ObjectHandle;

// Hide the gory details of resolving the shared ptr.
static std::shared_ptr<Object>* resolveHandle(ObjectHandle objectHandle)
{
    return static_cast<std::shared_ptr<Object>*>(objectHandle.ptr);
}

// Just a sample on how to fully resolve the object for internal use.
static Object* resolveObject(ObjectHandle objectHandle)
{
    return resolveHandle(objectHandle)->get();
}

// Public API functions.

ObjectHandle object_create(void)
{
    return ObjectHandle{new std::shared_ptr<Object>(new Object())};
}

ObjectHandle object_retain(ObjectHandle o)
{
    return ObjectHandle{new std::shared_ptr<Object>(*resolveHandle(o))};
}

void object_release(ObjectHandle o)
{
    delete resolveHandle(o);
}

Upvotes: 0

Uflex
Uflex

Reputation: 1426

You can use std::shared_ptr::get to retrieve the value of your pointer in your object_create.

I'm not sure that you should maintain object_retain or object_release as it is already automatically handled by the shared_ptr.

Do you want your library to be used by C code? If so then as @Angew pointed out in his comment, have a look at Boost.intrusive_ptr, it seems to be the best choice.

If you can assume that client code written in C will use the C library (which I think kind of make sense), then you can completely drop these functions and handle all internally. You can provide a raw pointer for compatibility with C api if you need to but all the lifetime management could be handled automatically with shared_ptr.

Upvotes: 1

Fred Foo
Fred Foo

Reputation: 363737

The problem with shared_ptr, as you'll have figured out already, is that you can't modify the reference count except by constructing or destroying instances. So no, there's no way to get this to work except by keeping a shared_ptr to every constructed Object around until its reference count drops to zero, but doing that right entails redoing much of the reference counting, so you gain very little.

Perhaps boost::intrusive_ptr is a better option.

Upvotes: 7

Related Questions