boost serialization, deserialization of raw C arrays
boost, boost-serialization, c++, serialization
Solution
I heartily recommend you use `std::array` or `std::vector` here, because... you messed this up :)
For starters, `Monkey` doesn't initialize its members. So, loading ends up doing a `load_binary` to whatever pointer value `m.arr` happened to have. How would you expect the deserialization to "know" that you needed to allocate memory for that? You need to tell it:
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);
}
Now, let's make `Monkey` a bit less unsafe (by adding initialization and destruction, and, perhaps most importantly, prohibiting copy semantics):
struct Monkey
{
uint32_t num;
float* arr;
Monkey() : num(0u), arr(nullptr) {}
Monkey(Monkey const&) = delete;
Monkey& operator=(Monkey const&) = delete;
~Monkey() { delete[] arr; }
};
Now, you can see it work:
#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, ";"));
}
Prints
0;1;2;3;4;5;6;7;8;9;
Live on Coliru
Problem
I'm trying to serialize and deserialize raw C pointers and their data, with the example below. It seems to serialize just fine, but I am unsure how to make it deserialize - it just crashes with a memory access violation exception when I deserialize it. I suppose it is because it dosn't know how to deserialize it, but where do I specify that? Using a vector is not an option, in very large primitive data amounts it is painfully slow ``` #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; } ```