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

如何让Boost反序列化时用object_pool分配std::map中的MyClass指针内存?

解决Boost序列化中反序列化指针来自object_pool的问题

你遇到的核心问题是:Boost默认的指针序列化逻辑会用全局new分配内存,导致反序列化后的MyClass*不属于object_pool,无法归还到池中复用。要解决这个问题,我们需要自定义反序列化时的对象构造逻辑,让Boost强制使用object_pool来创建对象。

核心思路

Boost序列化提供了boost::serialization::load_construct_data模板函数,允许我们完全控制对象在反序列化时的构造方式。我们可以通过这个函数,让反序列化过程使用object_pool分配内存并构造MyClass对象,同时利用Archive的上下文(Context)传递object_pool的引用。

修改后的完整代码

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/pool/object_pool.hpp>
#include <boost/serialization/map.hpp>
#include <map>
#include <iostream>
#include <sstream>
#include <string>
#include <functional>
#include <stdint.h>
#include <boost/any.hpp>

class MyClass {
public :
friend class boost::serialization::access;
MyClass():data(0) {
    std::cout << std::endl << "MyClass()" << std::endl ;
}
MyClass( uint32_t val):data(val) {
    std::cout << std::endl << "Parameterized MyClass()" << std::endl ;
}
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
    ar & data;
}
~MyClass(){}
friend std::ostream &operator<<( std::ostream &output, const MyClass &D ) {
    output << "Data : " << D.data ;
    return output;
}
void print() const {
    std::cout << std::endl << "Data : " << data << std::endl ;
}
private :
uint32_t data ;
};

// 特化load_construct_data,自定义MyClass对象的反序列化构造逻辑
namespace boost {
namespace serialization {

template<class Archive>
void load_construct_data(Archive & ar, MyClass *& t, const unsigned int version) {
    // 从Archive上下文获取object_pool指针
    auto* pool = boost::any_cast<boost::object_pool<MyClass>*>(ar.get_context());
    // 使用object_pool构造对象,替代默认的new
    t = pool->construct();
}

} // namespace serialization
} // namespace boost

int main() {
try {
    typedef std::map<int, MyClass *> ObjectMap ;
    ObjectMap map;
    boost::object_pool<MyClass> pool ;

    // 初始化map,用pool分配对象
    map[1] = pool.construct(6) ;
    map[2] = pool.construct(7) ;
    map[3] = pool.construct(8) ;
    map[4] = pool.construct(9) ;

    // 序列化
    std::stringbuf strbuf;
    boost::archive::binary_oarchive oa( strbuf ) ;
    oa << map;

    // 反序列化
    ObjectMap mapRoundTrip;
    boost::archive::binary_iarchive ia( strbuf ) ;
    // 将pool存入Archive的上下文,供load_construct_data使用
    ia.set_context(boost::any(&pool));
    ia >> mapRoundTrip ;

    // 验证反序列化结果,且指针来自pool
    std::cout << "\n反序列化后的对象数据:" << std::endl;
    for (const auto& pair : mapRoundTrip) {
        std::cout << "Key: " << pair.first << ", " << *pair.second << std::endl;
        // 可以安全地用pool销毁对象,归还内存到池中
        // pool.destroy(pair.second);
    }

} catch ( boost::archive::archive_exception &e ) {
    std::cout << std::endl << e.what() << std::endl ;
}
}

关键修改说明

  1. 特化load_construct_data:

    • 这个函数会在反序列化MyClass对象时被Boost自动调用,我们在这里替换了默认的new内存分配逻辑,改用object_pool::construct()创建对象。
    • 通过ar.get_context()获取之前存入的object_pool指针,确保构造的对象完全来自指定的内存池。
  2. 传递object_pool到Archive上下文:

    • 在创建binary_iarchive后,调用ia.set_context(boost::any(&pool))将内存池的指针存入Archive的上下文,让load_construct_data能够访问到它。
  3. 内存管理验证:

    • 反序列化后的mapRoundTrip中所有MyClass*指针都属于object_pool,你可以安全地使用pool.destroy()销毁对象,将内存归还到池中复用,完全符合你的需求。

注意事项

  • 如果你的场景存在对象共享(多个指针指向同一个MyClass实例),Boost的默认指针跟踪机制依然有效,我们只是替换了对象的构造方式,没有改变序列化的对象跟踪逻辑。
  • 务必保证object_pool的生命周期长于反序列化后的对象,避免池被提前销毁导致悬空指针。

内容的提问来源于stack exchange,提问作者Jerry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:10:51