如何让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 ; } }
关键修改说明
特化
load_construct_data:- 这个函数会在反序列化
MyClass对象时被Boost自动调用,我们在这里替换了默认的new内存分配逻辑,改用object_pool::construct()创建对象。 - 通过
ar.get_context()获取之前存入的object_pool指针,确保构造的对象完全来自指定的内存池。
- 这个函数会在反序列化
传递
object_pool到Archive上下文:- 在创建
binary_iarchive后,调用ia.set_context(boost::any(&pool))将内存池的指针存入Archive的上下文,让load_construct_data能够访问到它。
- 在创建
内存管理验证:
- 反序列化后的
mapRoundTrip中所有MyClass*指针都属于object_pool,你可以安全地使用pool.destroy()销毁对象,将内存归还到池中复用,完全符合你的需求。
- 反序列化后的
注意事项
- 如果你的场景存在对象共享(多个指针指向同一个
MyClass实例),Boost的默认指针跟踪机制依然有效,我们只是替换了对象的构造方式,没有改变序列化的对象跟踪逻辑。 - 务必保证
object_pool的生命周期长于反序列化后的对象,避免池被提前销毁导致悬空指针。
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

