【问题标题】:boost serialization, deserialization of raw C arraysboost序列化,原始C数组的反序列化
【发布时间】:2013-12-15 16:47:00
【问题描述】:

我正在尝试序列化和反序列化原始 C 指针及其数据,示例如下。它似乎可以很好地序列化,但我不确定如何使其反序列化 - 当我反序列化它时,它只会因内存访问冲突异常而崩溃。我想是因为它不知道如何反序列化它,但是我在哪里指定呢?

使用向量不是一种选择,在非常大的原始数据量中它非常缓慢

#include <stdint.h>
#include <string>
#include <iostream>
#include <fstream>
#pragma warning (push) 
#pragma warning( disable : 4244 ) 
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/array.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#pragma warning (pop) 

struct Monkey
{
    uint32_t num;
    float* arr;

};


namespace boost
{
    namespace serialization
    {
        template<class Archive>
        void serialize(Archive & ar, Monkey& m, const unsigned int version)
        {
            ar & m.num;
            ar & make_array<float>(m.arr, m.num);
        }
    }
}


int _tmain(int argc, _TCHAR* argv[])
{
    const char* name = "monkey.txt";

    {
        Monkey m;
        m.num = 10;
        m.arr = new float[m.num];
        for (uint32_t index = 0; index < m.num; index++)
            m.arr[index] = (float)index;

        std::ofstream outStream(name, std::ios::out | std::ios::binary | std::ios::trunc);
        boost::archive::binary_oarchive oar(outStream);
        oar << (m);
    }

    Monkey m;
    std::ifstream inStream(name, std::ios::in | std::ios::binary);     
    boost::archive::binary_iarchive iar(inStream);
    iar >> (m);

    return 0;
}

【问题讨论】:

    标签: c++ serialization boost boost-serialization


    【解决方案1】:

    我衷心推荐你在这里使用std::arraystd::vector,因为...你搞砸了:)

    对于初学者,Monkey 不会初始化其成员。因此,加载最终会执行 load_binary 到任何指针值 m.arr 碰巧有。您如何期望反序列化“知道”您需要为此分配内存?你需要告诉它

        template<class Archive>
        void serialize(Archive & ar, Monkey& m, const unsigned int version)
        {
            ar & m.num;
            if (Archive::is_loading::value)
            {
                assert(m.arr == nullptr);
                m.arr = new float[m.num];
            }
            ar & make_array<float>(m.arr, m.num);
        }
    

    现在,让我们降低Monkey 的不安全性(通过添加初始化和销毁​​,也许最重要的是,禁止复制语义):

    struct Monkey
    {
        uint32_t num;
        float* arr;
    
        Monkey() : num(0u), arr(nullptr) {}
    
        Monkey(Monkey const&) = delete;
        Monkey& operator=(Monkey const&) = delete;
        ~Monkey() { delete[] arr; }
    };
    

    现在,您可以看到它起作用了:

    #include <iostream>
    #include <fstream>
    #pragma warning(disable: 4244)
    #include <boost/serialization/serialization.hpp>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/archive/binary_iarchive.hpp>
    
    struct Monkey
    {
        uint32_t num;
        float* arr;
    
        Monkey() : num(0u), arr(nullptr) {}
    
        Monkey(Monkey const&) = delete;
        Monkey& operator=(Monkey const&) = delete;
        ~Monkey() { delete[] arr; }
    };
    
    namespace boost
    {
        namespace serialization
        {
            template<class Archive>
            void serialize(Archive & ar, Monkey& m, const unsigned int version)
            {
                ar & m.num;
                if (Archive::is_loading::value)
                {
                    assert(m.arr == nullptr);
                    m.arr = new float[m.num];
                }
                ar & make_array<float>(m.arr, m.num);
            }
        }
    }
    
    int main(int argc, char* argv[])
    {
        const char* name = "monkey.txt";
        {
            Monkey m;
            m.num = 10;
            m.arr = new float[m.num];
            for (uint32_t index = 0; index < m.num; index++)
                m.arr[index] = (float)index;
    
            std::ofstream outStream(name, std::ios::out | std::ios::binary | std::ios::trunc);
            boost::archive::binary_oarchive oar(outStream);
            oar << (m);
        }
    
        Monkey m;
        std::ifstream inStream(name, std::ios::in | std::ios::binary);
        boost::archive::binary_iarchive iar(inStream);
        iar >> (m);
    
        std::copy(m.arr, m.arr + m.num, std::ostream_iterator<float>(std::cout, ";"));
    }
    

    打印

    0;1;2;3;4;5;6;7;8;9;
    

    Live on Coliru

    【讨论】:

    • 我开始写自己的答案,但@sehe 已经把所有代码和所有问题都放好了。我只能添加我的摘要,只是改写这里的内容:您真正的问题不是反序列化本身,而是内存管理。您没有指定 struct Monkey 如何分配、复制或释放它使用的内存。 Sehe 提供了两种干净的方法来解决这个内存管理问题(使用向量或添加/删除复制 ctor、dtor 等)。
    【解决方案2】:

    在反序列化时,m.arr 不会初始化为 10 个浮点数的数组,而是初始化为 float*

    Monkey::arr 设为std::vector&lt;float&gt; 而不是float*。 Boost 序列化知道如何序列化和反序列化 C++ 标准库中的所有容器。

    【讨论】:

    • 我应该如何/在哪里分配这个内存,因为 m.num 可能是我在反序列化之前不知道的任意数字?
    • 我不知道。但是您可以将Monkey::arr 设为std::vector&lt;float&gt; 而不是float*。 Boost 序列化知道如何序列化和反序列化 C++ 标准库中的所有容器。
    • 很遗憾,我不能这样做;正如我在代码 sn-p 之前所写的那样,我正在处理大量数据(大量 3d 网格和图像数据)并且反序列化它太慢了(几分钟!)
    • 我想不出任何理由为什么反序列化到数组应该比反序列化到 std::vector 更快(除了 boost 方面的编码极差,但这不太可能)。如果此时代码速度很快,那是因为您没有反序列化整个数组。
    • 我完全同意奥斯瓦尔德。反序列化为向量会更慢是一个神话。一个完整的神话,因为库将甚至保证在加载数据之前使用实际尺寸调用.reserve(n)。并且 POD 类型使用优化的副本加载(相当于 memcpy
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-10
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    • 2016-07-13
    • 1970-01-01
    相关资源
    最近更新 更多