I want to implement a class in C++ whose purpose is implementing RAII mechanism for a C-style object.
Then, I need to be able to pass an instance of this class to all the C-style functions that receive the mentioned C-style object as argument. I know that this should be solved with unique_ptr
, but I cannot use C++11
for now. Anyway, I would like to understand how this should be made, regardless that there are better solutions.
I have several doubts regarding to which operators I must overload, and the difference beteween some of them.
Below is an example of code with the implementation I have made. I am specially confused with the operators 1 and 2 (what is the difference?)
I want to know if the code I have implemented covers all the use cases, I mean, all the scenarios where the C library could use the object. In addition, I would like to understand the difference between the operators 1 and 2.
// Example: a C-style library called "clib" which use an object called "cobj":
struct cobj {
int n;
};
void clib_create_cobj(struct cobj **obj) {
*obj = (struct cobj*)malloc(sizeof(cobj));
(*obj)->n = 25;
}
void clib_release_cobj(struct cobj *obj) {
free(obj);
}
void clib_doSomething(struct cobj *obj) {
std::cout << obj->n << std::endl;
}
// My wrapper class for implementing RAII
class CobjWrapper {
public:
CobjWrapper(struct cobj *obj) : m_obj (obj) { }
~CobjWrapper() {
if(m_obj != NULL) {
clib_release_cobj(m_obj);
m_obj = NULL;
}
}
operator struct cobj* () const { // (1)
return m_obj;
}
struct cobj& operator * () { // (2)
return *m_obj;
}
struct cobj** operator & () { // (3)
return &m_obj;
}
struct cobj* operator->() { // (4)
return m_obj;
}
private:
struct cobj *m_obj;
};
// The main method:
int main() {
struct cobj *obj = NULL;
clib_create_cobj(&obj);
CobjWrapper w(obj);
clib_doSomething(w);
return 0;
}
The above source can be tested here:
The following is an implicit cast
operator struct cobj* () const { // (1)
with example usage
CobjWrapper wrapper = /**/;
struct cobj* obj = wrapper;
whereas the following is the unary operator *
struct cobj& operator * () { // (2)
with example usage
CobjWrapper wrapper = /**/;
struct cobj& obj = *wrapper;
BTW, I would completely hide the C struct, something like:
class CobjWrapper {
struct ObjDeleter
{
void operator()(cobj *obj) const { clib_release_cobj(obj); }
};
public:
CobjWrapper()
{
cobj *obj = nullptr;
clib_create_cobj(&obj);
m_obj.reset(obj);
}
void doSomething() { clib_doSomething(m_obj.get()); }
private:
std::unique_ptr<cobj, ObjDeleter> m_obj;
};