Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

shared_ptr and the class factory

5.00/5 (1 vote)
9 Aug 2012CPOL1 min read 16.7K   67  
shared_ptr and the class factory

Introduction

We have a device manager that keeps track of currently attached devices. They happen to be USB devices but that is irrelevant. The issue we face is that devices can be attached or removed at any time. The class factory will scan the list of currently attached devices and if found, returns a shared_ptr to that device. If the device is removed the device manager will remove the object from the list, which will delete the object. This is bad news for any routines currently using a pointer to that object. The object needs to be kept alive until all routines using that device let go. This is an ideal application of the shared_ptr.

My problem is the usual hierarchy doesn’t work with shared_ptr.

C++
class Base {};
class DeviceOne : public Base {};
class DeviceTwo : public Base{};
shared_ptr<Base> classfactory( string const &dev ) {};

// compile error
shared_ptr<DeviceOne> d1 = classfactory( "deviceone");

// compile error	
shared_ptr<DeviceTwo> d2 = classfactory("devicetwo");

// can’t use d3 as a DeviceOne object		
shared_ptr<Base> d3 = classfactory("deviceone");

classfactory has to return a shared_ptr<Base>. The way I solved the problem was to define a class that keeps the device object alive by protecting the object instance, while allowing convenient access to what it points to. It does add another pointer to overhead, but I thought it was worth it. The extra pointer can be removed. Just modify the operator->() to return the dynamic_cast. Since there is a runtime penalty for dynamic_cast, I chose to only pay for that once, at the cost of the extra pointer memory.

C++
template<typename T>
class PDerrived 
{
public:
	PDerrived( shared_ptr<Base> p_ )
		: b(p_)					// keep the device alive
		, pd( dynamic_cast<T *>(p_.get()) )	// cached for convenience
	{}
    
    // convenient access to object
	T *operator->() const { return pd; }	
	
	// object created and correct type
	operator bool () const { return pd != nullptr; }
	
	// allows assignment to other shared_ptrs
	operator shared_ptr<Base> () const { return b; }	
private:
shared_ptr<Base>	b;
	T 			*pd;
};

//Now one can write
PDerrived <deviceOne> d1 = classfactory( "deviceone");
PDerrived <deviceTwo> d2 = classfactory("devicetwo");
PDerrived <Base> p = d1;

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)