You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在shared_ptr的use_count达特定值时触发事件并复用对象?

基于shared_ptr的对象复用与内存性能优化

问题描述

我的应用中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 09:35:35