在无序映射中插入智能指针调用析构函数

问题描述

我正在制作一个引擎并处理材质,我有一个静态渲染器类存储 static std::unordered_map<uint,Ref<Material>> m_Materials;(材质及其 ID),Ref 是使用下一个方法的共享指针:

template<typename T>
using Ref = std::shared_ptr<T>;

template<typename T,typename ... Args>
constexpr Ref<T> CreateRef(Args&& ... args) { return std::make_shared<T>(std::forward<Args>(args)...); }

template<typename T>
constexpr Ref<T> CreateRef(T* t) { return std::shared_ptr<T>(t); }

所以材质是一个简单的类,用一个 unsigned int (uint) 构造来存储它的 ID 和一个字符串来存储它的名称,并创建它们并存储它们,我在渲染器中有下一个静态函数:>

Ref<Material> Renderer::CreateMaterialWithID(uint material_id,const std::string& name)
{
    Ref<Material> mat = CreateRef<Material>(new Material(material_id,name));
    std::pair<uint,Ref<Material>> mat_pair(material_id,mat);

    m_Materials.insert(mat_pair);
    return mat;
}

问题是插入到map中,由于某种原因,调用了材质析构函数,导致插入了一个空的智能指针(虽然ID是正确插入的)[material_id,empty]

现在,材质和创建的对似乎正确存储了材质的数据,所以我不知道为什么它是贴图失败。我还尝试插入作为初始值设定项列表 ({material_id,mat}),将材料创建为 CreateRef<Material>(material_id,name)(没有 new),并且还使用 emplace 而不是 {{1 }} 但我总是得到相同的结果,我不明白为什么地图调用析构函数

有人看错了吗?

解决方法

尝试调用insert_or_assign;如果键已经存在,insert 将简单地销毁您尝试插入的对象。举个例子

m_Materials[0];
m_Materials.insert({0,std::make_shared<Material>(name)});

shared_ptr 将被丢弃,因为第一个 [0] 创建了一个 nullptr 值,并且插入稍后看到它并说“如果它已经存在就不要插入”。

m_Materials.insert_or_assign({0,std::make_shared<Material>(name)});

替换存储在那里的 nullptr,就像这样

m_Materials[0]=std::make_shared<Material>(name);

顺便说一句,我非常担心 CreateRef 有两个重载,一个接受构造函数参数,另一个是指针。这是一个混淆地图和领土的例子,我发现在烦人的时候在一个不舒服的地方咬你。