如何在shared_ptr的use_count达特定值时触发事件并复用对象?
问题描述
我的应用中new和malloc操作耗时极长,为了提升内存管理性能,我希望复用由shared_ptr包装的对象。目前的做法是当对象的use_count()达到特定值时,将其从容器中移除实现销毁,需要时再新建对象。我想知道是否能在use_count()达到特定值时触发事件(比如函数、lambda),这样就能把对象存入列表以待复用,而非直接销毁。
我的初步实现思路如下:
class MyClass { public: MyClass() {}; virtual ~MyClass() {} atomic<shared_ptr<MyClass>> next; }; // 预分配一块连续内存 vector<shared_ptr<MyClass>> memory; memory.reserve(SIZE); for(unsigned int i = 0; i < SIZE; ++i) memory.emplace_back(make_shared<MyClass>()); atomic<shared_ptr<MyClass>> pool = memory[0]; for(unsigned int i = 0; i < SIZE - 1; ++i) memory[i]->next = memory[i+1]; // 获取可复用对象(模拟创建) shared_ptr<MyClass> create() { // 这里需要保证原子操作 shared_ptr<MyClass> c = pool; pool = c->next; return c; } // 将对象放回复用池(当use_count为1时执行) void deletion_if_use_count_is_1(shared_ptr<MyClass> d) { // 这里需要保证原子操作 d->next = pool; pool = d; }
如代码所示,memory容器中的shared_ptr始终持有对象,导致对象的use_count()永远不会为0,但我希望在不改动shared_ptr本身的前提下实现对象复用,想知道是否有更优的实现方式。
优化方案
利用shared_ptr自定义删除器实现自动回收复用
shared_ptr支持自定义删除器,这是实现对象自动复用的核心:当最后一个外部使用者的shared_ptr被销毁时,自定义删除器会触发,将对象放回复用池,而非销毁对象。这样无需依赖use_count()的判断,就能实现自动回收。
实现步骤:
- 定义线程安全的对象池:用原子操作保证复用池的线程安全(单线程环境可简化)。
- 自定义删除器逻辑:让
shared_ptr的删除行为变为将对象放回池,而非调用delete。 - 预初始化对象池:一次性分配所有需要复用的对象,彻底避免后续
new/malloc操作。
示例代码:
#include <memory> #include <atomic> #include <vector> class MyClass { public: MyClass() {} // 重置对象状态,复用前必须清理内部数据 void reset() { // 根据实际需求重置成员变量,比如清空缓存、重置状态标记等 } std::atomic<std::shared_ptr<MyClass>> next; }; class ObjectPool { private: std::atomic<std::shared_ptr<MyClass>> pool_head; // 保存所有对象的强引用,防止对象被意外销毁 std::vector<std::shared_ptr<MyClass>> all_objects; public: explicit ObjectPool(size_t size) { all_objects.reserve(size); // 初始化链表结构的对象池 for (size_t i = 0; i < size; ++i) { auto obj = std::make_shared<MyClass>(); all_objects.push_back(obj); // 原子操作插入链表头部 std::shared_ptr<MyClass> current_head = pool_head.load(); obj->next = current_head; while (!pool_head.compare_exchange_weak(current_head, obj)) { obj->next = current_head; } } } // 获取复用对象 std::shared_ptr<MyClass> acquire() { std::shared_ptr<MyClass> obj; do { obj = pool_head.load(); if (!obj) { // 池为空时可选择新建或返回nullptr,此处示例返回nullptr return nullptr; } // 原子操作移除链表头部的对象 } while (!pool_head.compare_exchange_weak(obj, obj->next)); // 复用前重置对象状态 obj->reset(); // 自定义删除器:当shared_ptr计数归零时,将对象放回池 return std::shared_ptr<MyClass>(obj.get(), [this](MyClass* p) { auto sp = std::shared_ptr<MyClass>(p); // 原子操作将对象放回链表头部 std::shared_ptr<MyClass> current_head = pool_head.load(); sp->next = current_head; while (!pool_head.compare_exchange_weak(current_head, sp)) { sp->next = current_head; } }); } }; // 使用示例 int main() { const size_t POOL_SIZE = 100; ObjectPool pool(POOL_SIZE); // 获取对象 auto obj1 = pool.acquire(); // 使用对象... // 当obj1被销毁时,自定义删除器自动将对象放回池 obj1.reset(); // 再次获取到的是刚才放回的对象 auto obj2 = pool.acquire(); return 0; }
方案优势
- 自动回收:无需手动判断
use_count(),最后一个外部shared_ptr销毁时,对象自动回到复用池。 - 线程安全:通过
std::atomic的compare_exchange_weak实现无锁线程安全,高并发场景下性能优于互斥锁。 - 消除内存碎片:预分配所有对象,彻底解决动态内存分配的耗时问题。
- 无侵入性:仅通过自定义删除器实现逻辑,无需修改
shared_ptr本身。
注意事项
- 对象状态重置:复用对象前必须调用
reset()清理内部状态,避免旧数据干扰新场景。 - 池大小规划:根据业务并发量合理设置池大小,可扩展动态扩容逻辑(会引入少量
new操作)。 - 线程安全验证:多线程环境下需确保对象池存取逻辑的线程安全性,上述无锁实现依赖
std::atomic的正确使用。
内容的提问来源于stack exchange,提问作者lxndr
相关产品推荐
相关产品推荐

