使用Boost的Serialization库序列化STL标准容器

栏目: 编程工具 · 发布时间: 6年前

内容简介:使用Boost做对象序列化是非常方便的,本文将介绍一种序列化STL标准容器的方法。这是之前设计的异步框架的一个子功能:过程A将标准容器数据序列化成二进制流,然后将该二进制数据发送到过程B,过程B将数据反序列化为标准容器。下面这个基类支持vector、set、unordered set、multiset、unordered multiset、map、unordered map、multimap和unordered multimap。

使用Boost做对象序列化是非常方便的,本文将介绍一种序列化STL标准容器的方法。

这是之前设计的异步框架的一个子功能:过程A将标准容器数据序列化成二进制流,然后将该二进制数据发送到过程B,过程B将数据反序列化为标准容器。 (转载请指明出于breaksoftware的csdn博客)

下面这个基类支持vector、set、unordered set、multiset、unordered multiset、map、unordered map、multimap和unordered multimap。

/*************************************************************************
    > File Name: serialization.h
    > Author: fangliang
    > Mail: fangliang1988@gmail.com 
    > Created Time: Fri 23 Mar 2018 03:11:14 PM CST
 ************************************************************************/
#ifndef STLSERIALIZATION_SERIALIZATION_H
#define STLSERIALIZATION_SERIALIZATION_H

#include <string>
#include <sstream>
#include <boost/archive/binary_oarchive.hpp>  
#include <boost/archive/binary_iarchive.hpp>  

namespace stl_serialization {

template<class T>
class Serialization : public T {
public:

    void serialization(std::ostringstream& ostream) {
        boost::archive::binary_oarchive oa(ostream);
        oa << *this;
    }

    void unserialization(std::istringstream& istream) {
        boost::archive::binary_iarchive ia(istream);
        ia >> *this;
    }
private:  
    friend class boost::serialization::access;  

    template<class Archive>  
    void serialize(Archive& ar, const unsigned int version) {  
        ar & boost::serialization::base_object<T>(*this);  
    }
};

}

#endif // STLSERIALIZATION_SERIALIZATION_H

可被序列化的标准容器只要继承该基类即可。以map为例

/*************************************************************************
    > File Name: map_serialization.h
    > Author: fangliang
    > Mail: fangliang1988@gmail.com 
    > Created Time: Thu 22 Mar 2018 11:09:11 PM CST
 ************************************************************************/
#ifndef STLSERIALIZATION_MAP_SERIALIZATION_H
#define STLSERIALIZATION_MAP_SERIALIZATION_H

#include <map>
#include <string>
#include <sstream>
#include <boost/serialization/map.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

#include "serialization.h"

namespace stl_serialization {

template<class T, class T1>
class MapSerialization : public Serialization<std::map<T, T1> > {
};

}

#endif // STLSERIALIZATION_MAP_SERIALIZATION_H

使用一个单元测试来测试这段代码

/*************************************************************************
    > File Name: ut_map_serialization.cpp
    > Author: fangliang
    > Mail: fangliang1988@gmail.com 
    > Created Time: Thu 22 Mar 2018 11:11:46 PM CST
 ************************************************************************/
#include "gtest/gtest.h"
#include "./src/stl_serialization/map_serialization.h"

using stl_serialization::MapSerialization;

int main(int argc, char* argv[]) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

namespace unit_test {

class UtMapSerialization :
    public ::testing::Test 
{
protected:
    virtual void SetUp() {
        MapSerialization<int, std::string> ms_src;
        for (int i = 0; i < _size; i++) {
            ms_src[i] = " ";
        }
        ms_src.serialization(_ost);
    }
    virtual void TearDown() {}
protected:
    int _size = 10000;
    std::ostringstream _ost;
};

TEST_F(UtMapSerialization, SizeEq) {
    MapSerialization<int, std::string> ms_des;
    std::istringstream ist(_ost.str());
    ms_des.unserialization(ist);
    ASSERT_EQ(_size, ms_des.size());
}

TEST_F(UtMapSerialization, ElemEq) {
    MapSerialization<int, std::string> ms_des;
    std::istringstream ist(_ost.str());
    ms_des.unserialization(ist);
    int i = 0;
    for (std::map<int, std::string>::iterator it = ms_des.begin(); it != ms_des.end(); it++) {
        ASSERT_EQ(it->first, i++);
    }
}

}

如果STL的容器中存放在的是一个非标准类型,比如一个用户自定义类型,则需要让该类型实现serialize方法。以vector为例

/*************************************************************************
    > File Name: vector_serialization.h
    > Author: fangliang
    > Mail: fangliang1988@gmail.com 
    > Created Time: Thu 22 Mar 2018 03:41:16 PM CST
 ************************************************************************/
#ifndef STLSERIALIZATION_VECTOR_SERIALIZATION_H
#define STLSERIALIZATION_VECTOR_SERIALIZATION_H

#include <vector>
#include <string>
#include <sstream>
#include <boost/serialization/vector.hpp>
#include <boost/archive/binary_oarchive.hpp>  
#include <boost/archive/binary_iarchive.hpp>  

#include "serialization.h"

namespace stl_serialization {

template<class T>
class VectorSerialization : public Serialization<std::vector<T> > {
};

}

#endif // STLSERIALIZATION_VECTOR_SERIALIZATION_H

下面代码中,由于TestData是容器承载的类型,所以它需要增加24~33行代码用于容器内对象序列化。

/*************************************************************************
    > File Name: ut_vecotr_serialization.cpp
    > Author: fangliang
    > Mail: fangliang1988@gmail.com 
    > Created Time: Wed 21 Mar 2018 02:34:18 PM CST
 ************************************************************************/
#include "gtest/gtest.h"
#include "./src/stl_serialization/vector_serialization.h"

using stl_serialization::VectorSerialization;

int main(int argc, char* argv[]) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

namespace unit_test {

struct TestData {
    int interger;
    double db;
    float fl;
    std::string str;
private:  
    friend class boost::serialization::access;  

    template<class Archive>  
    void serialize(Archive& ar, const unsigned int version) {  
        ar & interger;
        ar & db;
        ar & fl;
        ar & str;
    }
};

class UtVectorSerialization :
    public ::testing::Test 
{
protected:
    virtual void SetUp() {
        VectorSerialization<int> vs_src;
        for (int i = 0; i < _size; i++) {
            TestData item;
            item.interger = i;
            item.db = i;
            item.fl = i;
            item.str = std::to_string(i);
            vs_src.push_back(item);
        }
        vs_src.serialization(_ost);
    }
    virtual void TearDown() {}
protected:
    int _size = 10000;
    std::ostringstream _ost;
};

TEST_F(UtVectorSerialization, SizeEq) {
    VectorSerialization<int> vs_des;
    std::istringstream ist(_ost.str());
    vs_des.unserialization(ist);
    ASSERT_EQ(_size, vs_des.size());
}

TEST_F(UtVectorSerialization, ElemEq) {
    VectorSerialization<int> vs_des;
    std::istringstream ist(_ost.str());
    vs_des.unserialization(ist);
    for (int i = 0; i < _size; i++) {
        const TestData& item = vs_des.at(i);
        ASSERT_EQ(item.interger, i);
        ASSERT_DOUBLE_EQ(item.db, i);
        ASSERT_FLOAT_EQ(item.db, i);
        std::string str = std::to_string(i);
        ASSERT_STREQ(item.str.c_str(), str.c_str());  
    }
}

}

最后我们看下包含10000个对象的容器反序列化耗时,总体来说效率还是不错的。

使用Boost的Serialization库序列化STL标准容器

最后说下,unordered set、unordered multiset、unordered map和unordered multimap等不保证序列化前后容器中元素顺序一致。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Wireshark网络分析就这么简单

Wireshark网络分析就这么简单

林沛满 / 人民邮电出版社 / 2014-11-6 / 39.00

Wireshark可能是世界上最好的开源网络包分析器,能在多种平台上(比如Windows、Linux和Mac)抓取和分析网络包,在IT业界有着广泛的应用。 《Wireshark网络分析就这么简单》采用诙谐风趣的手法,由浅入深地用Wireshark分析了常见的网络协议,读者在学习Wireshark的同时,也会在不知不觉中理解这些协议。作者还通过身边发生的一些真实案例,分享了Wireshark的......一起来看看 《Wireshark网络分析就这么简单》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具