提升二进制序列化 - 固定长度错误的双数组

时间:2015-02-18 18:16:04

标签: c++ arrays serialization boost binary

我正在创建一个类,它存储了许多用于使用boost保存/加载的双精度数。负载需要尽可能快,因此实现二进制格式是目标。

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

vector<DataChunk>

其中DataChunk存储一个固定长度的双数组

double data[2048]

当我使用文本存档(text_iarchive)测试功能时,一切都很好。但是,在使用二进制存档时,我会在反序列化类时遇到内存访问冲突。

更奇怪的是,如果我用相同的双精度值填充双数组(即数据的所有元素[2048]等于12345),它就可以工作。然而,不同的双值似乎会使它崩溃(见下文)。

这是我的RawData类:

#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();
};

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

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;
}

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

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;

1 个答案:

答案 0 :(得分:1)

您需要使用

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

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

这是演示,自包含:

<强> 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 << ", ";
    }
}