This is becoming a common pattern in my code, for when I need to manage an object that needs to be noncopyable because either A. it is \"heavy\" or B. it is an operating sys
A partial solution is to use make_shared
to create your shared_ptr
s. For example,
auto my_thing = std::make_shared<Thing>();
instead of
auto my_thing = std::shared_ptr<Thing>(new Thing);
It's still non-intrusive, so nothing else needs to change. Good implementations of make_shared
combine the memory allocation for the reference count and the object itself. That saves a memory allocation and keeps the count close to the object for better locality. It's not quite as efficient as something like boost:intrusive_ptr
, but it's worth considering.
you can save some overhead by simply getting rid of the two classes and having just one and typedefing a shared ptr to it - this is the idom i use all the time
class Resource
{
...
};
typedef boost::shared_ptr<Resource> ResourcePtr;
If you want to reduce the overhead of distinct memory allocations for your object and the reference counter, you could try to use make_shared. That's what its for.
Use a boost::intrusive_ptr which is designed to work on a class with an embedded reference count.
Non-tested example based on example here:
class Resource;
class Implementation : public boost::noncopyable
{
friend class Resource;
HANDLE someData;
int refCount; // The reference count.
Implementation(HANDLE input) : someData(input) { refCount = 0; };
void SomeMethodThatActsOnHandle() {
//Do stuff
};
public:
~Implementation() { FreeHandle(someData) };
};
intrusive_ptr_add_ref(Implementation* imp) { imp->refCount++; }
intrusive_ptr_release(Implementation* imp) { if(--imp->refCount) == 0) delete imp; }
class Resource
{
boost::intrusive_ptr<Implementation> impl;
public:
Resource(int argA) explicit {
HANDLE handle =
SomeLegacyCApiThatMakesSomething(argA);
if (handle == INVALID_HANDLE_VALUE)
throw SomeTypeOfException();
impl.reset(new Implementation(handle));
};
void SomeMethodThatActsOnTheResource() {
impl->SomeMethodThatActsOnTheHandle();
};
};