Click here to Skip to main content
15,866,422 members
Articles / Programming Languages / C++
Tip/Trick

shared_ptr and the class factory

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
9 Aug 2012CPOL1 min read 16K   68   4   2
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)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Manish K. Agarwal24-Aug-12 1:01
Manish K. Agarwal24-Aug-12 1:01 
Questionnice tip Pin
Volynsky Alex9-Aug-12 14:29
professionalVolynsky Alex9-Aug-12 14:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.