C ++ Boost std :: map二进制序列化,包含从Boost object_pool构造的指针 [英] C++ Boost binary serialization of std::map containing pointers constructed from Boost object_pool

查看:138
本文介绍了C ++ Boost std :: map二进制序列化,包含从Boost object_pool构造的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序具有"MyClass"类.它的对象是从Boost Object_pool构造的.

My application has a class "MyClass". It's objects are being constructed from the Boost Object_pool.

我需要通过Boost Binary序列化对包含这些对象的std :: map进行序列化/反序列化.

I need to serialized/de serialize a std::map containing these objects as value via Boost Binary Serialization.

用于序列化-

我从池中获取一个指针,执行一些操作,将其插入std :: map中,然后通过Boost二进制序列化对其进行序列化.

I take a pointer from the pool, do some operations, insert it in the std::map and serialize it via Boost binary serialization.

用于反序列化-

我获取了该序列化的缓冲区,并使用Boost二进制序列化对其进行了反序列化.反序列化成功完成,但是在此过程中,不是通过对象池构造的Boost序列化机制为指针分配了新的内存.

I fetch that serialized buffer and de-serialize it with Boost binary serialization. De-serialization happens successfully, but during the process new memory is being allocated for the pointers by Boost Serialization mechanism which is not constructed from the Object Pool.

因此,我将无法重用boost序列化机制分配的内存,因为它不是由池中构造的,因此无法归还给对象池.

Hence, I won't be able to reuse this memory allocated by the boost serialization mechanism as it cannot be given back to the object pool because it was not constructed from the 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>

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.print() ;
      return output;
    }

   void print()
   {
      std::cout << std::endl << "Data : " << data << std::endl ;
   }


   private :
   uint32_t data ;
};

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

    ObjectMap map;

     boost::object_pool<MyClass> pool ;

     map[1] = pool.construct(6) ;
     map[2] = pool.construct(7) ;
     map[3] = pool.construct(8) ;
     map[4] = pool.construct(9) ;

     // Serialization
     std::stringbuf strbuf;
      boost::archive::binary_oarchive oa( strbuf ) ;
      oa << map;


     // Deserialzation
      ObjectMap mapRoundTrip;

      boost::archive::binary_iarchive ia( strbuf ) ;
      ia >> mapRoundTrip ;
    }
    catch ( boost::archive::archive_exception &e )
    {
      std::cout << std::endl << e.what() << std::endl ;
    }
 }  

我的要求是在反序列化期间,使用从object_pool中获取的指针填充地图.

My requirement is to populate the map, during deserialzation, with pointers fetched from the object_pool.

推荐答案

这是实现Boost序列化方式的限制.它不只是复制指针地址,还取消了对指针的引用并复制了整个对象.这是对所有STL容器完成的.反序列化时,使用标准分配器创建一个新对象.

This is a limitation of the way Boost serialization is implemented. Instead of just copying the pointer address, it de-references pointers and copies the whole object. This is done for all STL containers. When de-serializing, a new object is created, using standard allocator.

有两种方法可以避免这种情况:通过构建自定义映射类或使用pool_allocator.

There are two ways to circumvent this: by building custom map class or by using the pool_allocator.

您可以通过不使用STL容器来避免这种情况.编写自己的地图(包装器).例如

You can circumvent this by not using the STL containers. Write your own map (wrapper). E.g.

#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 <map>
#include <iostream>
#include <sstream>

class MyClass
{
public:
    friend class boost::serialization::access;
    MyClass() { std::cout << "MyClass()\n"; }
    MyClass(int val) :data(val) { std::cout << "MyClass(" << val << ")\n";  }

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version) { ar & data; }

    void print() { std::cout << "Data : " << data << "\n"; }
private:
    int data;
};

template<class Key, class T>
class MyMap
{
public:
    MyMap(boost::object_pool<T> &pool) : mr_pool(pool) {}

    ~MyMap()
    {
        for (auto& kv : m_map)
        {
            if (kv.second != nullptr) mr_pool.destroy(kv.second);
            kv.second = nullptr;
        }
    }

    typename std::map<Key, T*>::iterator begin() { return m_map.begin(); }
    typename std::map<Key, T*>::iterator end() { return m_map.end(); }

    template<class ... Types>
    void construct(const Key& key, Types ... args)
    {
        m_map[key] = mr_pool.construct(args...);
    }

    template<class Archive>
    void save(Archive & ar, const unsigned int version) const
    {
        ar << m_map.size();
        for (auto& kv : m_map)
        {
            ar << kv.first;
            ar << boost::serialization::binary_object(kv.second, sizeof(T));
        }
    }

    template<class Archive>
    void load(Archive & ar, const unsigned int version)
    {
        size_t size;
        ar >> size;
        for (size_t i = 0; i<size; i++)
        {
            Key key;
            ar >> key;
            T* prt = mr_pool.construct();
            ar >> boost::serialization::make_binary_object(prt, sizeof(T));
            m_map[key] = prt;
        }
    }

    template<class Archive>
    void serialize(Archive & ar, const unsigned int file_version)
    {
        boost::serialization::split_member(ar, *this, file_version);
    }
private:
    boost::object_pool<T>& mr_pool;
    std::map<Key, T*> m_map;
};

int main()
{
    try
    {
        using ObjectMap = MyMap<int, MyClass>;

        boost::object_pool<MyClass> pool;
        ObjectMap map(pool);

        map.construct(1, 6);
        map.construct(2, 7);
        map.construct(3, 8);
        map.construct(4, 9);

        // Serialization
        std::stringbuf strbuf;
        boost::archive::binary_oarchive oa(strbuf);
        oa << map;

        for (auto& kv : map) {
            std::cout << "map: " << kv.first << ", ";
            kv.second->print();
        }
        std::cout << "pre destory\n";
        for (auto& kv : map) {
            std::cout << "map: " << kv.first << ", data addr: " << kv.second << "\n";
        }

        for (auto& kv : map) {
            if (kv.second != nullptr) pool.destroy(kv.second);
            kv.second = nullptr;
        }

        std::cout << "post destroy\n";
        for (auto& kv : map) {
            std::cout << "map: " << kv.first << ", data addr: "  << kv.second << "\n";
        }

        MyClass* temp = pool.construct(10); // to create memory offset
        // Deserialzation
        ObjectMap mapRoundTrip(pool);

        boost::archive::binary_iarchive ia(strbuf);
        ia >> mapRoundTrip;

        for (auto& kv : mapRoundTrip) {
            std::cout << "mapRoundTrip: " << kv.first << ", data addr: " << kv.second << "\n";
        }
        for (auto& kv : mapRoundTrip) {
            std::cout << "mapRoundTrip: " << kv.first << ", ";
            kv.second->print();
        }

        pool.destroy(temp);
        temp = nullptr;
    }
    catch (boost::archive::archive_exception &e)
    {
        std::cout << std::endl << e.what() << std::endl;
    }
    return 0;
}

输出:

MyClass(6)
MyClass(7)
MyClass(8)
MyClass(9)
map: 1, Data : 6
map: 2, Data : 7
map: 3, Data : 8
map: 4, Data : 9
pre destory
map: 1, data addr: 0x24ad720
map: 2, data addr: 0x24ad728
map: 3, data addr: 0x24ad730
map: 4, data addr: 0x24ad738
post destroy
map: 1, data addr: 0
map: 2, data addr: 0
map: 3, data addr: 0
map: 4, data addr: 0
MyClass(10)
MyClass()
MyClass()
MyClass()
MyClass()
mapRoundTrip: 1, data addr: 0x24ad728
mapRoundTrip: 2, data addr: 0x24ad730
mapRoundTrip: 3, data addr: 0x24ad738
mapRoundTrip: 4, data addr: 0x24ad740
mapRoundTrip: 1, Data : 6
mapRoundTrip: 2, Data : 7
mapRoundTrip: 3, Data : 8
mapRoundTrip: 4, Data : 9

演示

或者,您可以不使用标准分配器,而使用池分配器来规避此问题.例如

Alternatively you can circumvent this by not using the standard allocator, but instead use the pool allocator. E.g.

#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/pool/pool_alloc.hpp>
#include <boost/serialization/map.hpp>
#include <map>
#include <iostream>
#include <sstream>

class MyClass
{
public:
    friend class boost::serialization::access;
    MyClass() { std::cout << "MyClass empty construct\n"; }
    MyClass(MyClass const& src) :data(src.data) { std::cout << "MyClass copy construct\n"; }
    void swap(MyClass& src) noexcept { std::swap(data, src.data); }
    MyClass(MyClass&& src) :MyClass() { src.swap(*this); std::cout << "MyClass move construct\n"; }

    MyClass(int val) :data(val) { std::cout << "MyClass data construct (" << val << ")\n"; }

    MyClass& operator=(MyClass src) { src.swap(*this); return *this; }

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version) { ar & data; }

    void print() { std::cout << "Data : " << data << "\n"; }
private:
    int data;
};

int main()
{
    using ObjectMap = std::map<int, MyClass, std::less<int>, boost::pool_allocator<MyClass>>;
    using Pool = boost::singleton_pool<boost::pool_allocator_tag, sizeof(ObjectMap::value_type)>;

    try
    {
        ObjectMap map;

        map[1] = MyClass(6);
        map[2] = MyClass(7);
        map[3] = MyClass(8);
        map[4] = MyClass(9);

        // Serialization
        std::stringbuf strbuf;
        boost::archive::binary_oarchive oa(strbuf);
        oa << map;

        for (auto& kv : map) {
            std::cout << "map: " << kv.first << ", ";
            kv.second.print();
        }
        std::cout << "pre destory\n";
        for (auto& kv : map) {
            std::cout << "map: " << kv.first << ", data addr: " << &kv.second << "\n";
        }

        map.clear();
        Pool::purge_memory();

        map[5] = MyClass(10);

        std::cout << "post destroy and reassign\n";
        for (auto& kv : map) {
            std::cout << "map: " << kv.first << ", data addr: " << &kv.second << "\n";
        }

        // Deserialzation
        ObjectMap mapRoundTrip;

        boost::archive::binary_iarchive ia(strbuf);
        ia >> mapRoundTrip;

        for (auto& kv : mapRoundTrip) {
            std::cout << "mapRoundTrip: " << kv.first << ", data addr: " << &kv.second << "\n";
        }
        for (auto& kv : mapRoundTrip) {
            std::cout << "mapRoundTrip: " << kv.first << ", ";
            kv.second.print();
        }

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

    return 0;
}

输出:

MyClass data construct (6)
MyClass empty construct
MyClass data construct (7)
MyClass empty construct
MyClass data construct (8)
MyClass empty construct
MyClass data construct (9)
MyClass empty construct
map: 1, Data : 6
map: 2, Data : 7
map: 3, Data : 8
map: 4, Data : 9
pre destory
map: 1, data addr: 0x118e604
map: 2, data addr: 0x118e62c
map: 3, data addr: 0x118e654
map: 4, data addr: 0x118e67c
MyClass data construct (10)
MyClass empty construct
post destroy and reassign
map: 5, data addr: 0x118e604
MyClass empty construct
MyClass empty construct
MyClass move construct
MyClass empty construct
MyClass empty construct
MyClass move construct
MyClass empty construct
MyClass empty construct
MyClass move construct
MyClass empty construct
MyClass empty construct
MyClass move construct
mapRoundTrip: 1, data addr: 0x118e62c
mapRoundTrip: 2, data addr: 0x118e654
mapRoundTrip: 3, data addr: 0x118e67c
mapRoundTrip: 4, data addr: 0x118e6a4
mapRoundTrip: 1, Data : 6
mapRoundTrip: 2, Data : 7
mapRoundTrip: 3, Data : 8
mapRoundTrip: 4, Data : 9

您可以通过检查地址来查看内存池的重用方式.

You can see how the memory pool is being reused by checking the addresses.

演示

这篇关于C ++ Boost std :: map二进制序列化,包含从Boost object_pool构造的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆