如何实现删除vector中std::shared_ptr时同步删除unordered_map中指向同一对象的指针——自定义shared_ptr删除器的编写方法
这个需求很有意思,核心是要让vector里的shared_ptr销毁时自动同步清理unordered_map里的对应条目,保证两者的一致性。咱们一步步来实现这个自定义删除器,顺便聊聊设计上的关键细节。
首先得明确几个核心逻辑:
- 删除器需要能访问到
World类里的organisms_map,所以得让它能拿到World的实例引用。 - 删除器要知道该从
map里移除哪个键,所以每个Organism得关联对应的坐标键,或者创建shared_ptr时把键传给删除器。 - 要满足“不在
animals_vector中的对象必然不在organisms_map中”,map里不能持有强引用——不然就算vector里的shared_ptr被移除,map的强引用会让对象继续存活,破坏一致性。所以map应该存weak_ptr而非shared_ptr。
第一步:给Organism添加键成员
先给Organism加个成员变量存储对应的坐标键,这样删除器能直接从对象拿到要移除的键:
class Organism { public: int m_key; // 存储转换后的坐标int值,和map的键严格对应 // 你的其他成员和业务逻辑... };
第二步:实现带自定义删除器的shared_ptr创建
在World的add_organism方法里,创建Organism实例时构造shared_ptr并传入自定义删除器。这个删除器用lambda捕获World的this指针,从而能直接操作organisms_map:
class World { private: unordered_map<int, std::weak_ptr<Organism>> organisms_map; // 改用weak_ptr避免强引用 vector<std::shared_ptr<Organism>> animals_vector; public: void add_organism(int key) { // 创建Organism实例并设置对应键 auto* organism = new Organism(); organism->m_key = key; // 构造带自定义删除器的shared_ptr std::shared_ptr<Organism> org_ptr(organism, [this](Organism* ptr) { // 1. 先从map中移除对应的条目 organisms_map.erase(ptr->m_key); // 2. 再销毁Organism对象 delete ptr; }); // 将shared_ptr加入vector,同时给map存对应的weak_ptr animals_vector.push_back(org_ptr); organisms_map[key] = org_ptr; } // 示例:从map中查找有效对象的方法 std::shared_ptr<Organism> find_organism(int key) { auto it = organisms_map.find(key); if (it != organisms_map.end()) { auto sp = it->second.lock(); // 尝试获取强引用,检查是否过期 if (sp) { return sp; } // 如果weak_ptr已过期,顺便清理map里的无效条目 organisms_map.erase(it); } return nullptr; } };
设计逻辑说明
- 删除器的作用:当
vector里的shared_ptr被销毁(比如vector被清空、元素被移除且无其他强引用),引用计数降为0,触发删除器。删除器先从map里移除对应键,再销毁Organism对象,完美同步两者的状态。 - 用
weak_ptr存map:这样map不会持有对象的强引用,对象的生命周期完全由vector里的shared_ptr控制。只要vector里没了对象,map里的weak_ptr会过期,我们可以在查找时清理无效条目,或者定期维护。
注意事项
- 线程安全:如果是多线程环境,对
organisms_map和animals_vector的所有操作要加锁(比如用std::mutex),避免并发修改导致的未定义行为。 - 键的一致性:必须确保
Organism::m_key和map的键完全一致,否则删除器会移除错误的条目。 - 避免悬空引用:不要在
World外部保存Organism的裸指针或强引用,不然会破坏“vector是唯一强引用源”的设计逻辑。
内容的提问来源于stack exchange,提问作者Michał Turek
相关产品推荐
相关产品推荐

