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

Boost binary serialization - double array of fixed length error

本文关键字:错误 数组 二进制 序列化 Boost      更新时间:2023-10-16

我正在创建一个类,它存储了大量的doubles,用于保存/加载boost。负载需要尽可能快,所以让二进制格式工作是我们的目标。

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

vector<DataChunk>

其中DataChunk存储固定长度的双阵列

double data[2048]

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

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

这是我的RawData类:

#pragma once
#include <boostserializationvector.hpp>
#include <boostserializationarray.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;

您需要使用

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

这是演示,自包含:

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