Is there a way to manually increment and decrement the count of a shared_ptr in C++?
The problem that I am trying to solve is as follows. I am writing a library in C
If you want maximum security, gives the user a handle, not the pointer. This way, there's no way he will try to free
it and half-succeed.
I'll assume below that, for simplicity's sake, you'll give the user the object pointer.
You should create a manager class, as described by Matthieu M. in his answer, to memorize what was acquired/unacquired by the user.
As the inferface is C, you can't expect him to use delete
or whatever. So, a header like:
#ifndef MY_STRUCT_H
#define MY_STRUCT_H
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
typedef struct MyStructDef{} MyStruct ; // dummy declaration, to help
// the compiler not mix types
MyStruct * MyStruct_new() ;
size_t MyStruct_getSomeValue(MyStruct * p) ;
void MyStruct_delete(MyStruct * p) ;
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // MY_STRUCT_H
Will enable the user to use your class. I used a declaration of a dummy struct because I want to help the C user by not imposing him the use of the generic void *
pointer. But using void *
is still a good thing.
The C++ source implementing the feature would be:
#include "MyClass.hpp"
#include "MyStruct.h"
MyManager g_oManager ; // object managing the shared instances
// of your class
extern "C"
{
MyStruct * MyStruct_new()
{
MyClass * pMyClass = g_oManager.createMyClass() ;
MyStruct * pMyStruct = reinterpret_cast(pMyClass) ;
return pMyStruct ;
}
size_t MyStruct_getSomeValue(MyStruct * p)
{
MyClass * pMyClass = reinterpret_cast(p) ;
if(g_oManager.isMyClassExisting(pMyClass))
{
return pMyClass->getSomeValue() ;
}
else
{
// Oops... the user made a mistake
// Handle it the way you want...
}
return 0 ;
}
void MyStruct_delete(MyStruct * p)
{
MyClass * pMyClass = reinterpret_cast(p) ;
g_oManager.destroyMyClass(pMyClass) ;
}
}
Note that the pointer to MyStruct is plain invalid. You should not use it for whatever reason without reinterpret_cast-ing it into its original MyClass type (see Jaif's answer for more info on that. The C user will use it only with the associated MyStruct_* functions.
Note too that this code verify the class does exist. This could be overkill, but it is a possible use of a manager (see below)
The manager will hold, as suggested by Matthieu M., a map containing the shared pointer as a value (and the pointer itself, or the handle, as the key). Or a multimap, if it is possible for the user to somehow acquire the same object multiple times.
The good thing about the use of a manager will be that your C++ code will be able to trace which objects were not "unacquired" correctly by the user (adding info in the acquire/unacquire methods like __FILE__
and __LINE__
could help narrow the bug search).
Thus the manager will be able to: