C++ 调用std:make_通过std::函数共享

C++ 调用std:make_通过std::函数共享,c++,c++11,stl,C++,C++11,Stl,我已经使用新的C++11特性构建了一个工厂模式。为了实现这一点,在注册表中注册了std::函数。现在我尝试实现实例化部分。现在它是这样实现的: 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)()

我已经使用新的C++11特性构建了一个工厂模式。为了实现这一点,在注册表中注册了std::函数。现在我尝试实现实例化部分。现在它是这样实现的:

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)());
}
std::map::iterator it=m_creators.find(id);
if(it!=m_creators.end())
{
返回std::shared_ptr((it->second)();
}

问题是,这显然不是异常保存,我正在尝试用等效的std::make_共享调用替换std::shared_ptr调用。函数是一个create函数,它只调用对象子类的构造函数。问题是我不知道如何使用std::函数来代替std::make shared中对构造函数的调用。这可能吗?

我会让std::函数返回一个共享的ptr,而不是一个裸指针。然后可以在std::函数中使用make_shared

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>();
    }
}
typedef std::map CreatorMap;
CreatorMap::iterator it=m_creators.find(id);
if(it!=m_creators.end())
{
返回(it->second)();
}
//创造者的例子
结构创建者{
公众:
std::shared_ptr运算符()(){
返回std::make_shared();
}
}

这还允许工厂更灵活地使用自定义删除程序。

您拥有的代码并非异常不安全。如果初始化过程中发生异常,则接受指针的
共享\u ptr
构造函数将调用托管指针上的
删除

摘自N3797,§20.8.2.2.1/7

模板显式共享ptr(Y*p)

……
异常安全:如果引发异常,则调用
delete p

如果这让您感觉更好,您可以将
map
类型更改为

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

shared_ptr
s可以从
unique_ptr
s构建,在这种情况下,您永远不会传递原始指针。但这是不必要的,因为我上面引用了一个条款。

当您拥有的解决方案可以正常工作时,为什么要使用
make_shared
?如果你看到,例如,
std::make_shared
不再是异常安全的。为什么它不是异常安全的?@JoachimPileborg,公平地说,“为什么”,正是他问这个问题的原因,也许可以用你的经验来做:)@JoachimPileborg它不是异常安全的,因为可以创建一个类实例,而共享的\u ptr会引发异常。在这种情况下,将不调用delete,这将导致内存泄漏。使用make_shared不是这种情况。@这是不正确的;如果
shared\u ptr
在构建过程中抛出异常,它将
删除传递给它的指针。下面我的答案中有相关的标准引用。这个类在工厂std::function的重载函数调用操作符中是新的,如果在新的和返回之间抛出了什么呢?不太可能,但可能。@PorkyBrain好吧,这将是工厂函数编写方式中的一个错误。无论如何,“我的编辑”解决了这个问题。虽然OP没有要求,但这仍然不允许工厂向共享指针添加自定义删除器,因为不存在需要自定义删除器的可破坏类型或自定义分配器。@PorkyBrain是的,假设他的每个多态类型都需要具有不同签名的删除器,至少可以说,这是不寻常的。让工厂返回一个
shared\u ptr
意味着调用者不能
release()
托管指针,这就是为什么我更喜欢
unique\u ptr
方法。谢谢,为什么我没有想到这一点。很简单。