boost serialization, deserialization of raw C arrays
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
How to serialize large malloc'ed float array with Boost allocated outside of constructor?
According to this answer, you can do it like this:
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);
}
Deserializing array of string with boost and are bigger than expected (after serializing from cv::cuda::GpuMat)
In PrepData
, string are initialized without a given length, leading to arbitrary long string (until null '\0' is reached).
The correct code is :
string strX((const char*)matX.col(0).data, matX.rows);
string strY((const char*)matY.col(0).data, matY.rows);
Direct boost serialization to char array
IIUC, you would like to write to a preallocated array of fixed size.
You could use a boost::iostreams::array_sink (wrapped with stream to give it an std::ostream interface) for that.
Unsigned long long serialization in boost
Serializing unsigned long long
arrays works for me using gcc 4.7.2 with boost 1.49, gcc 4.2.1 with boost 1.55, and clang 3.4 with boost 1.55:
#include <sstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/version.hpp>
struct Foo {
unsigned long long bar[3];
template<class Archive>
void serialize(Archive& ar, const unsigned int /*version*/) {
ar & bar;
}
};
std::ostream& operator<<(std::ostream& os, const Foo& foo) {
return os << foo.bar[0] << ' ' << foo.bar[1] << ' ' << foo.bar[2];
}
int main() {
std::cout << "Boost version " << BOOST_LIB_VERSION << '\n';
Foo before;
before.bar[0] = 0;
before.bar[1] = 1;
before.bar[2] = 2;
std::cout << "before: " << before << '\n';
std::ostringstream os;
{
boost::archive::text_oarchive oa(os);
oa << before;
}
Foo after;
{
std::istringstream is(os.str());
boost::archive::text_iarchive ia(is);
ia >> after;
}
std::cout << "after: " << after << '\n';
return 0;
}
Here's gcc 4.8 with boost 1.55 on Coliru, also works.
If you are using a pointer to an allocated array, then I think that is your problem. I don't believe you can serialize a bare pointer to a primitive, and I'm sure you can't serialize a bare pointer to an array of primitives because there is no way for serialization to know how many elements a pointer points to.
I would use a std::vector
over an allocated array because there is no speed disadvantage in doing so. However, if you really want to allocate your own array then you can serialize it with the boost::serialization::make_array()
wrapper like this:
#include <iostream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/array.hpp>
struct Foo {
size_t dataSize;
unsigned long long *data;
Foo()
: dataSize(3)
, data(new unsigned long long[dataSize]) {
}
~Foo() {
delete[] data;
}
// TODO: Production code should disallow default copy constructor
// and assignment operator.
template<class Archive>
void serialize(Archive& ar, const unsigned int /*version*/) {
ar & dataSize;
ar & boost::serialization::make_array(data, dataSize);
}
};
int main() {
Foo foo;
foo.data[0] = 0;
foo.data[1] = 1;
foo.data[2] = 2;
boost::archive::text_oarchive oa(std::cout);
oa << foo;
return 0;
}
It turns out that this question was not about unsigned long long
at all, but is essentially a duplicate of boost serialization, deserialization of raw C arrays.
Boost serialization of class wrapping a pointer
The solution to the riddle is simply that serializing primitive types through a pointer is not supported.
The reason is that object tracking is disabled for primitive types. this is documented here:
Special Considerations / Object Tracking
By default, data types designated primitive by Implementation Level class serialization trait are never tracked. If it is desired to track a shared primitive object through a pointer (e.g. a long used as a reference count), It should be wrapped in a class/struct so that it is an identifiable type. The alternative of changing the implementation level of a long would affect all longs serialized in the whole program - probably not what one would intend.
Here's a minimalist sample that shows the root cause in isolation:
Live On Coliru
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <iostream>
#include <sstream>
int main() {
// Serialization for double* does not compile
double* p(new double(2.0));
std::cout << *p << std::endl;
std::ostringstream oss;
boost::archive::xml_oarchive oa(oss);
oa << BOOST_SERIALIZATION_NVP(p);
std::cout << oss.str() << std::endl;
}
You need to rethink your serialization plan. What object identity do you wish/need to track?
You can track the identity of the Ptr<>
object, and from the fact that you took the trouble toimplement a custom pointer wrapper type, I get the impression that this is likely all you want/need.
Demo: Live On Coliru
In the unlikely event that you really want bi-level object tracking here (e.g. if you can have two Ptr<T>
instances pointing to the same T
?) you will need to partially specialize for the case where T is a primitive type.
looking for deserialization example in boost
You were almost there:
int main()
{
using namespace mydata;
MyData data { "this is a name", "this is a type", boost::make_shared<MyInfo>("this is info") };
std::ostringstream oss;
{
boost::archive::text_oarchive oa(oss);
oa << data;
}
std::istringstream iss(oss.str());
{
boost::archive::text_iarchive ia(iss);
ia >> data;
}
}
In fact, you could use std::stringstream
for both the input and output, but for purity I showed the symmetric approaches (which does redundant copying).
You'll need
#include <sstream>
#include <boost/archive/text_iarchive.hpp>
and for deserialization your classes need to be defaultconstructible:
MyInfo(std::string info = "") : info(std::move(info)) {}
(unrelated warning: do not use std::string info = {}
here because that triggers a compiler bug in MSVC)
Here's a fully working sample that shows that the deserialized object has the same data: Live On Coliru
#include <boost/serialization/access.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <sstream>
#include <boost/archive/text_iarchive.hpp>
namespace mydata
{
struct MyInfo
{
std::string info = "extra info";
MyInfo(std::string info = "") : info(std::move(info)) {}
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int /*version*/)
{
ar & info;
}
};
struct MyData
{
std::string name;
std::string type;
boost::shared_ptr<MyInfo> myref;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int /*version*/)
{
ar & name;
ar & type;
ar & myref;
}
};
}
int main()
{
using namespace mydata;
std::ostringstream oss;
{
MyData data { "this is a name", "this is a type", boost::make_shared<MyInfo>("this is info") };
boost::archive::text_oarchive oa(oss);
oa << data;
}
MyData cloned;
std::istringstream iss(oss.str());
{
boost::archive::text_iarchive ia(iss);
ia >> cloned;
}
// check equality
{
std::ostringstream oss2;
boost::archive::text_oarchive oa(oss2);
oa << cloned;
std::cout << oss.str() << "\n";
std::cout << oss2.str() << "\n";
}
}
Output:
22 serialization::archive 10 0 0 14 this is a name 14 this is a type 0 1 2 1 0
0 12 this is info
22 serialization::archive 10 0 0 14 this is a name 14 this is a type 0 1 2 1 0
0 12 this is info
Related Topics
Plug-In Architecture Based C/C++ Application
Allowing Access to Private Members
Why Uninitialized Global Variable Is Weak Symbol
How to Restart Linux from Inside a C++ Program
How to Subtract Two Gettimeofday Instances
How to Compile: Unrecognized Relocation
C++: How to Check Type of Files Without Extension
How to Add Playable(Such as Wav,Wmv) Header with Pcm Data/Buffer in iOS
What Is The Reason for Having Unreserved Identifiers as Built-In Macros in Gcc
C++11 Random Number Distributions Are Not Consistent Across Platforms -- What Alternatives Are There
How to Know If Std::Map Insert Succeeded or Failed
How to Get a List Video Capture Devices Names (Web Cameras) Using Qt (Crossplatform)? (C++)
Setting File Permissions When Opening a File with Ofstream
Enumerate Com Object (Idispatch) Methods Using Atl
Setting Extra Bits in a Bool Makes It True and False at the Same Time