I'm learning C++ while I run into this situation, where I want to implement an equivalently efficient version in C++ of the following symbolic code in C.
<header.h>
struct Obj;
Obj* create(...);
void do_some_thing(Obj*);
void do_another_thing(Obj*);
void destroy(Obj*);
The requirements are:
- The implementation is provided in a library (static/dynamic) and the header doesn't expose any detail other than the interface
- It should be equally efficient
Exposing an interface (COM-like) with virtual functions doesn't qualify; that's a solution to enable polymorphism (more than one implementation exposed through the same interface) which isn't the case, and since I don't need the value it brings, I can't see why I should pay the cost of calling functions through 2 indirect pointers. So my next thought was the pimpl idiom:
<header.h>
class Obj {
public:
Obj();
~Obj();
void do_some_thing();
void do_another_thing();
private:
class Impl;
smart_ptr<Impl> impl_; // ! What should I use here, unique_ptr<> or shared_ptr<> ?
};
shared_ptr<> doesn't seem to qualify, I would pay for unnecessary interlocked increment/decrement that didn't exist in the original implementation. On the other hand unique_ptr<> makes Obj non-copyable. This means that the client can't call his own functions that take Obj by value, and Obj is merely a wrapper for a pointer, so essentially he can't pass pointers by value! He could do that in the original version. (passing by reference still doesn't qualify: he's still passing a pointer to a pointer)
So what should be the equally efficient way to implement this in C++?
EDIT: I gave it some more thought and I came to this solution:
<header.h>
class ObjRef // I exist only to provide an interface to implementation
{ // (without virtual functions and their double-level indirect pointers)
public:
ObjRef();
ObjRef(ObjRef); // I simply copy pointers value
ObjRef operator=(ObjRef); // ...
void do_some_thing();
void do_another_thing();
protected:
class Impl;
Impl* impl_; // raw pointer here, I'm not responsible for lifetime management
};
class Obj : public ObjRef
{
Obj(Obj const&); // I'm not copyable
Obj& operator=(Obj const&); // or assignable
public:
Obj(Obj&&); // but I'm movable (I'll have to implement unique_ptr<> functionality)
Obj& operator=(Obj&&);
Obj();
~Obj(); // I destroy impl_
// and expose the interface of ObjRef through inheritance
};
Now I return to client Obj, and If client needs to distribute the usage of Obj by calling some other his functions, he can declare them as
void use_obj(ObjRef o);
// and call them:
Obj o = call_my_lib_factory();
use_obj(o);