evotion
evotion

Reputation: 365

calling std:make_shared via a std::function

I have build a factory pattern using new C++11 features. To achieve this a std::function is registered in the registry. Now I am trying to implement the instantiation part. Right now it is implemented like this:

std::map<uint32_t, std::function<Class*()>>::iterator it = m_creators.find(id);
if(it != m_creators.end())
{
    return std::shared_ptr<Class>((it->second)());
}

The problem is, that is is obviously not exception save and I am trying to replace the std::shared_ptr call with a equivalent std::make_shared call. The std::function is a create function that only calls the constructor of a Object subclass. The problem is that I have no idea how to use the std::function instead of the call to the constructor in std::make shared. Is this even possible?

Upvotes: 1

Views: 1690

Answers (2)

Praetorian
Praetorian

Reputation: 109149

The code you have is not exception unsafe. The shared_ptr constructor that takes a pointer will call delete on the managed pointer if an exception occurs during initialization.

From N3797, §20.8.2.2.1/7

template<class Y> explicit shared_ptr(Y* p);
...
Exception safety: If an exception is thrown, delete p is called.

If it makes you feel better, you could change the map type to

std::map<uint32_t, std::function<std::unique_ptr<Class>()>>

shared_ptrs can be constructed from unique_ptrs, and you're never passing around a raw pointer in this case. But it is unnecessary because of the clause I quoted above.

Upvotes: 1

odinthenerd
odinthenerd

Reputation: 5552

I would make the std::function return a shared_ptr rather than a naked pointer. Then you could use make_shared inside the std::function.

typedef std::map<uint32_t, std::function<std::shared_ptr<Class>()>> CreatorMap;
CreatorMap::iterator it = m_creators.find(id);
if(it != m_creators.end())
{
    return (it->second)();
}

// example of a creator

struct SomeCreator{
public:
    std::shared_ptr<Class> operator()(){
        return std::make_shared<Class>();
    }
}

this also allows more flexibility to allow the factory to use custom deleter.

Upvotes: 2

Related Questions