提高二进制序列化 - 固定长度的误差双阵列 [英] Boost binary serialization - double array of fixed length error

查看:186
本文介绍了提高二进制序列化 - 固定长度的误差双阵列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要创建一个存储大量的双打与升压保存/加载的类。负载必须尽可能快,所以得到的二进制格式来工作的目标。

基本上,我有一个存储结构的向量类:

 矢量<&DataChunk GT;

在这里DataChunk存储固定长度的双阵列

 双数据[2048]

当我使用文本存档(text_iarchive)测试功能,一切都很正常。但是,使用二进制归档的时候,我得到的内存访问违反了反序列化的类。

更奇怪的是,如果我填用相同的双值双阵列(即数据[2048]等于12345的所有元素),它的工作原理。不同的双重价值似乎崩溃了,虽然(见下文)。

下面是我的RAWDATA类:

 的#pragma一次
#包括LT&;升压\\序列\\ vector.hpp>
#包括LT&;升压\\序列\\ array.hpp>使用命名空间std;结构DataChunk
{
上市:
    双数据[2048]; //这是有问题的区域
    INT结束;
私人的:
    友元类的boost ::系列化::访问;
    模板<类归档和GT;
    无效连载(归档和放大器; AR,const的无符号整型版)
    {
        AR&安培;数据;
        AR&安培;结束;
    }
};
类RAWDATA
{
私人的:
    矢量< DataChunk>块;
    友元类的boost ::系列化::访问;
    模板<类归档和GT;
    无效连载(归档和放大器; AR,const的无符号整型版)
    {
        AR&安培;块;
    }
上市:
    无效add_chunk(DataChunk块){chunks.push_back(块);};
    矢量< DataChunk> get_chunks(){返回块;};
    静态无效保存(RAWDATA路字符串路径);
    静态布尔载荷(RAWDATA&安培;第三,串路径);
    无效add_raw_data(矢量<&双GT; raw_data);
    矢量<&双GT; combine_chunks();
};

我的保存和载入功能,如下所示:

 无效RAWDATA ::保存(RAWDATA路路径字符串)
{
    的std :: ofstream的文件(路径);
    如果(file.good())
    {        提高::档案:: binary_oarchive OA(文件​​的std :: IOS ::二进制);
        //提振::档案:: text_oarchive的OA(文件​​);
        OA<< RD;
    }
    file.flush();
    file.close();
}布尔RAWDATA ::负载(RAWDATA&安培;第三,路径字符串)
{
    性病:: ifstream的文件(路径);
    如果(file.good())
    {        提高::档案:: binary_iarchive IA(文件的std :: IOS ::二进制);
        //提振::档案:: text_iarchive IA(文件);
        IA>> RD;
        file.close();
        返回true;
    }
    其他
        返回false;
}

在我的主要功能,我测试它是这样的:

 路径字符串=test.data;
RAWDATA OLD_DATA;
矢量<&双GT;原始数据;
的for(int i = 0; I< 5000;我++)
    raw_data.push_back(我* 2048); //更改为恒定值和它的作品...
old_data.add_raw_data(raw_data);//连载
RAWDATA ::保存(OLD_DATA,路径);//反序列化
RAWDATA NEW_DATA;
RAWDATA ::负载(NEW_DATA,路径);//抢块和测试值
矢量< DataChunk> chunks_in = new_data.get_chunks();
的for(int i = 0; I< chunks_in.size();我++)
    对于(INT J = 0; J< chunks_in [I] .END; J ++)
        COUT&所述;&下; chunks_in [I]的.data [j]的&下;&下;,;
返回0;


解决方案

您将需要使用

 模板<类归档和GT;无效连载(归档和放大器; AR,无符号){
    AR&安培;结束;
    AR&安培;提高::系列化:: make_array(数据结束);
}

请参阅的http://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/wrappers.html#arrays

下面是演示,整装的:

<大骨节病> 住在Coliru

 的#include&LT;升压/系列化/ vector.hpp&GT;
#包括LT&;升压/系列化/ array.hpp&GT;结构DataChunk {
  上市:
    双数据[2048]; //这是有问题的区域
    INT结束;  私人的:
    友元类的boost ::系列化::访问;
    模板&LT;类归档和GT;无效连载(归档和放大器; AR,无符号){
        AR&安培;结束;
        AR&安培;提高::系列化:: make_array(数据结束);
    }
};#包括LT&;升压/ range.hpp&GT;
#包括LT&;升压/范围/ algorithm.hpp&GT;类RAWDATA {
  私人的:
    的std ::矢量&lt;&DataChunk GT;块;
    友元类的boost ::系列化::访问;
    模板&LT;类归档和GT;无效连载(归档和放大器; AR,无符号){AR&放大器;大块; }  上市:
    无效add_chunk(DataChunk块){chunks.push_back(块); };
    的std ::矢量&lt;&DataChunk GT; get_chunks(){返回块; };
    静态无效保存(RAWDATA路的std ::字符串路径);
    静态布尔载荷(RAWDATA&安培;第三,标准::字符串路径);    无效add_raw_data(性病::矢量&lt;&双GT; raw_data){
        DataChunk块;
        汽车常量CSIZE =提振::大小(chunk.data);        为size_t N = raw_data.size()
               权衡= 0ul;        而(N 0){
            汽车N_ =的std ::分(N,CSIZE);
            的std :: copy_n(raw_data.begin()+附加赛,N_,chunk.data);
            chunk.end = N_;
            chunks.push_back(块);
            权衡+ = N_;
            N - = N_;
        }
    }    的std ::矢量&lt;&双GT; combine_chunks(){
        的std ::矢量&lt;&双GT; - [R;
        提高:: for_each的(块,[&安培; R](DataChunk常量和C){性病:: copy_n(c.data,c.end,back_inserter(R));});
        返回ř;
    }
};#包括LT&;升压/存档/ binary_oarchive.hpp&GT;
#包括LT&;升压/存档/ binary_iarchive.hpp&GT;
#包括LT&;&的fstream GT;无效RAWDATA ::保存(RAWDATA路的std ::字符串路径){
    的std :: ofstream的文件(路径);
    如果(file.good()){        提高::档案:: binary_oarchive OA(文件​​的std :: IOS ::二进制);
        //提振::档案:: text_oarchive的OA(文件​​);
        OA&LT;&LT; RD;
    }
    file.flush();
    file.close();
}布尔RAWDATA ::负载(RAWDATA&安培;第三,标准::字符串路径){
    性病:: ifstream的文件(路径);
    如果(file.good()){        提高::档案:: binary_iarchive IA(文件的std :: IOS ::二进制);
        //提振::档案:: text_iarchive IA(文件);
        IA&GT;&GT; RD;
        file.close();
        返回true;
    }其他
        返回false;
}#包括LT&;&iostream的GT;RAWDATA产生(){
    RAWDATA数据;
    的std ::矢量&lt;&双GT;原始数据;
    的for(int i = 0; I&LT; 5000;我++)
        raw_data.push_back(我* 2048);
    data.add_raw_data(raw_data);
    返回的数据;
}诠释主(){
    标准::字符串常量路径=test.data;    {
        //连载
        RAWDATA常量OLD_DATA =生成();
        RAWDATA ::保存(OLD_DATA,路径);
    }    {
        //反序列化
        RAWDATA NEW_DATA;
        RAWDATA ::负载(NEW_DATA,路径);        //抢块和测试值
        为(自动D:new_data.combine_chunks())
            性病::法院LT&;&LT; D&LT;&LT; ,;
    }
}

I'm creating a class that stores lots of doubles for saving/loading with boost. The load needs to be as fast as possible, so getting the binary format to work is the goal.

Basically, I have a class that stores a vector of structs:

vector<DataChunk>

where DataChunk stores a double array of fixed length

double data[2048]

When I test the functionality with using a text archive (text_iarchive), everything works great. However, when using the binary archive, I get memory access violation on deserializing the class.

More bizarrely, if I fill the double array with the same double value (i.e all elements of data[2048] are equal to 12345), it works. Varying double values seems to crash it, though (see below).

Here's my RawData class:

#pragma once
#include <boost\serialization\vector.hpp>
#include <boost\serialization\array.hpp>

using namespace std;

struct DataChunk
{
public:
    double data[2048]; //THIS IS THE PROBLEM AREA
    int end;
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& ar, const unsigned int version)
    {
        ar & data;
        ar & end;
    }
};


class RawData
{
private:
    vector<DataChunk> chunks;
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& ar, const unsigned int version)
    {
        ar & chunks;
    }
public:
    void add_chunk(DataChunk chunk){chunks.push_back(chunk);};
    vector<DataChunk> get_chunks(){return chunks;};
    static void save(RawData rd, string path);
    static bool load(RawData & rd, string path);
    void add_raw_data(vector<double> raw_data);
    vector<double> combine_chunks();
};

My save and load functions look like this:

void RawData::save(RawData rd, string path)
{
    std::ofstream file(path); 
    if(file.good())
    {

        boost::archive::binary_oarchive oa(file, std::ios::binary);
        //boost::archive::text_oarchive oa(file);
        oa << rd;
    }
    file.flush();
    file.close();
}

bool RawData::load(RawData & rd, string path)
{
    std::ifstream file(path);
    if(file.good())
    {

        boost::archive::binary_iarchive ia(file, std::ios::binary); 
        //boost::archive::text_iarchive ia(file);
        ia >> rd;
        file.close();
        return true;
    }
    else
        return false;
}

In my main function, I test it like this:

string path = "test.data";
RawData old_data;
vector<double> raw_data;
for(int i = 0; i < 5000; i++)
    raw_data.push_back(i * 2048); //change this to constant value and it works...
old_data.add_raw_data(raw_data);

//serialize
RawData::save(old_data, path);

//deserialize
RawData new_data;
RawData::load(new_data, path);

//grab the chunks and test the values
vector<DataChunk> chunks_in = new_data.get_chunks();
for(int i = 0; i < chunks_in.size(); i++)
    for(int j = 0; j < chunks_in[i].end; j++)
        cout<<chunks_in[i].data[j]<<", ";
return 0;

解决方案

You will want to use

template <class Archive> void serialize(Archive &ar, unsigned) {
    ar & end;
    ar & boost::serialization::make_array(data, end);
}

See http://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/wrappers.html#arrays

Here is the demo, selfcontained:

Live On Coliru

#include <boost/serialization/vector.hpp>
#include <boost/serialization/array.hpp>

struct DataChunk {
  public:
    double data[2048]; // THIS IS THE PROBLEM AREA
    int end;

  private:
    friend class boost::serialization::access;
    template <class Archive> void serialize(Archive &ar, unsigned) {
        ar & end;
        ar & boost::serialization::make_array(data, end);
    }
};

#include <boost/range.hpp>
#include <boost/range/algorithm.hpp>

class RawData {
  private:
    std::vector<DataChunk> chunks;
    friend class boost::serialization::access;
    template <class Archive> void serialize(Archive &ar, unsigned) { ar &chunks; }

  public:
    void add_chunk(DataChunk chunk) { chunks.push_back(chunk); };
    std::vector<DataChunk> get_chunks() { return chunks; };
    static void save(RawData rd, std::string path);
    static bool load(RawData &rd, std::string path);

    void add_raw_data(std::vector<double> raw_data) {
        DataChunk chunk;
        auto const csize = boost::size(chunk.data);

        size_t n    = raw_data.size(), 
               offs = 0ul;

        while (n>0) {
            auto n_ = std::min(n, csize);
            std::copy_n(raw_data.begin() + offs, n_, chunk.data);
            chunk.end = n_;
            chunks.push_back(chunk);
            offs += n_;
            n    -= n_;
        }
    }

    std::vector<double> combine_chunks() {
        std::vector<double> r;
        boost::for_each(chunks, [&r](DataChunk const& c) {std::copy_n(c.data, c.end, back_inserter(r));});
        return r;
    }
};

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <fstream>

void RawData::save(RawData rd, std::string path) {
    std::ofstream file(path);
    if (file.good()) {

        boost::archive::binary_oarchive oa(file, std::ios::binary);
        // boost::archive::text_oarchive oa(file);
        oa << rd;
    }
    file.flush();
    file.close();
}

bool RawData::load(RawData &rd, std::string path) {
    std::ifstream file(path);
    if (file.good()) {

        boost::archive::binary_iarchive ia(file, std::ios::binary);
        // boost::archive::text_iarchive ia(file);
        ia >> rd;
        file.close();
        return true;
    } else
        return false;
}

#include <iostream>

RawData generate() {
    RawData data;
    std::vector<double> raw_data;
    for (int i = 0; i < 5000; i++)
        raw_data.push_back(i * 2048);
    data.add_raw_data(raw_data);
    return data;
}

int main() {
    std::string const path = "test.data";

    {
        // serialize
        RawData const old_data = generate();
        RawData::save(old_data, path);
    }

    {
        // deserialize
        RawData new_data;
        RawData::load(new_data, path);

        // grab the chunks and test the values
        for (auto d : new_data.combine_chunks())
            std::cout << d << ", ";
    }
}

这篇关于提高二进制序列化 - 固定长度的误差双阵列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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