I have a class A, which contains the object of class B and I want to serialize it. The problem is, the class C inherits from B, so A can contain an object of either B or C. How can I efficiently implement the serialization with Boost?
My attempt is below, but I'm getting the error when trying to serialize A with C object, while with B it works correctly. Do you know, what am I doing wrong?
I've found some information about class-hierarchy objects serialization here, but it requires an explicit registration of the type in text_iarchive, whereas I need it to be registered in the A class because I'm not directly serializing B objects.
My attempt:
#include <fstream>
#include <iostream>
#include <vector>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
class B {
friend class boost::serialization::access;
private:
template<class Archive>
void save(Archive & ar, const unsigned int version) const {
ar & this->v->size();
for(int i = 0; i < this->v->size(); i++) {
ar & (*(this->v))[i];
}
};
template<class Archive>
void load(Archive & ar, const unsigned int version) {
size_t size;
int tmp;
ar & size;
this->v = new std::vector<int>(size);
for(int i = 0; i < size; i++) {
ar & tmp;
(*this->v)[i] = tmp;
}
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
protected:
std::vector<int>* v;
public:
B();
B(std::vector<int>* v);
virtual void print_vals();
};
B::B() {
this->v = nullptr;
}
B::B(std::vector<int>* v) {
this->v = v;
}
void B::print_vals() {
for(auto e : *(this->v)) {
std::cout << e << std::endl;
}
}
class C : public B {
friend class boost::serialization::access;
private:
int num2;
template<class Archive>
void serialize(Archive & ar, const unsigned int version){
ar & boost::serialization::base_object<B>(*this);
ar & num2;
};
public:
void print_vals() override {
for(auto e : *(this->v)) {
std::cout << e << std::endl;
}
std::cout << this->num2 << std::endl;
}
C();
C(int num2, std::vector<int>* v);
};
C::C() {
this->num2 = -1;
this->v = nullptr;
}
C::C(int num2, std::vector<int> *v) {
this->num2 = num2;
this->v = v;
}
class A {
friend class boost::serialization::access;
private:
int num;
B* b_obj;
template<class Archive>
void serialize(Archive & ar, const unsigned int version){
ar & num;
ar & b_obj;
};
public:
A();
A(int num, B* b);
void print_vals();
};
A::A() {
this->num = -1;
this->b_obj = nullptr;
}
A::A(int num, B* b) {
this->num = num;
this->b_obj = b;
}
void A::print_vals() {
std::cout << this->num << std::endl;
this->b_obj->print_vals();
}
int main() {
std::vector<int> v{1,2,3};
B b = B(&v);
A a(4, &b);
std::cout << "a:" << std::endl;
a.print_vals();
std::ofstream ofs("a.txt");
{
boost::archive::text_oarchive oa(ofs);
oa << a;
ofs.close();
}
A a2;
std::ifstream ifs("a.txt");
{
boost::archive::text_iarchive ia(ifs);
ia >> a2;
ifs.close();
}
std::cout << "a2:" << std::endl;
a2.print_vals();
C c(2, &v);
A a3(6, &c);
std::cout << "a3:" << std::endl;
a3.print_vals();
std::ofstream ofs2("a3.txt");
{
boost::archive::text_oarchive oa(ofs2);
oa << a3;
ofs.close();
}
A a4;
std::ifstream ifs2("a3.txt");
{
boost::archive::text_iarchive ia(ifs2);
ia >> a4;
ifs.close();
}
std::cout << "a4:" << std::endl;
a4.print_vals();
}
OUTPUT:
a:
4
1
2
3
a2:
4
1
2
3
a3:
6
1
2
3
2
terminate called after throwing an instance of 'boost::archive::archive_exception'
what(): unregistered class - derived class not registered or exported
Signal: SIGABRT (Aborted)
It turns that you have missed BOOST_CLASS_EXPORTfor derived class, i.e.
BOOST_CLASS_EXPORT(C)
Boost serialization cannot serialize pointer to derived object correctly without this macro.
You can find full working code here
Related
I saved objects to file and while reading them back i want to write it content to output stream. I did add operator overloading for it friend std::ostream& operator<<(std::ostream& out, T& c) but how to do it in correct way?
#include <iostream>
#include <fstream>
class MySpecificClass {
std::string data;
unsigned int x;
unsigned int y;
unsigned int z;
public:
MySpecificClass(): data(""), x(0), y(0), z(0) {}
MySpecificClass(std::string s, unsigned int xx, unsigned int yy, unsigned zz) : data(s), x(xx), y(yy), z(zz) {}
std::string Print() {
std::string s = "data: " + data + "\tx=" + std::to_string(x) + ",\ty=" + std::to_string(y) + ",\tz=" + std::to_string(z);
return s;
}
};
template <class T>
class IFileClass {
public:
IFileClass(std::string f) : fileName(f) {}
virtual void save(T& c) = 0;
virtual void read(T& c) = 0;
protected:
std::string fileName;
std::ofstream fout;
std::ifstream fin;
};
template <class T>
class FileWithClass : public IFileClass<T> {
public:
FileWithClass(std::string fn) : IFileClass<T>(fn) {
std::cout << "FileWithClass constructor" << std::endl;
}
friend std::ostream& operator<<(std::ostream& out, T& c) {
out << c.Print();
return out;
}
void save(T& c) override {
if (this->fileName == "")
throw new std::runtime_error("path is empty");
this->fout.open(this->fileName, std::ofstream::app);
if (this->fout.is_open()) {
this->fout.write((char*)&c, sizeof(T));
this->fout.close();
std::cout << "saved" << std::endl;
} else {
std::cout << "File open error" << std::endl;
}
}
void read(T& c) override {
if (this->fileName == "")
throw new std::runtime_error("path is empty");
this->fin.open(this->fileName);
if (this->fin.is_open()) {
while (this->fin.read((char*)&c, sizeof(T))) {
std::cout << c << std::endl;
}
this->fin.close();
} else {
std::cout << "File open error" << std::endl;
}
}
};
int main() {
MySpecificClass msc = {"My text", 1, 2, 3};
FileWithClass<MySpecificClass> fsv = {"test.txt"};
fsv.save(msc);
fsv.read(msc);
}
In line std::cout << c << std::endl; I get a compile error:
main.cpp|71|error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'MySpecificClass')
Basically this, outside of your class definition:
std::ostream& operator<<(std::ostream& out, MySpecificClass& c) {
out << c.Print();
return out;
}
You don't need to add the friend function definition, because you are not using any private members in your operator<<. And if you were, you would actually need to declare it friend in MySpecificClass, and not your template, because your template class has no access to MySpecificClass private data.
I have successfully serialized armadillo without a class matrices here:
#include <iostream>
#include <fstream>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <armadillo>
#include <boost/serialization/split_member.hpp>
BOOST_SERIALIZATION_SPLIT_FREE(arma::mat)
namespace boost {
namespace serialization {
template<class Archive>
void save(Archive & ar, const arma::mat &t, unsigned int version)
{
ar & t.n_rows;
ar & t.n_cols;
const double *data = t.memptr();
for(int K=0; K<t.n_elem; ++K)
ar & data[K];
}
template<class Archive>
void load(Archive & ar, arma::mat &t, unsigned int version)
{
int rows, cols;
ar & rows;
ar & cols;
t.set_size(rows, cols);
double *data = t.memptr();
for(int K=0; K<t.n_elem; ++K)
ar & data[K];
}
}}
int main() {
arma::mat A = arma::randu<arma::mat>(4,5);
std::ofstream outputStream;
outputStream.open("bin.dat");
std::ostringstream oss;
boost::archive::binary_oarchive oa(outputStream);
oa & A;
outputStream.close();
arma::mat B;
std::ifstream inputStream;
inputStream.open("bin.dat", std::ifstream::in);
boost::archive::binary_iarchive ia(inputStream);
ia & B;
return 0;
}
But my end goal is to have arma matrices within a class, alongside typical data types (int, double, float, etc.) and be able to either serialize everything or specific data from the class. I also got it to work, that the normal data types could be serialized:
#include <iostream>
#include <fstream>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <sstream>
#include <boost/serialization/split_member.hpp>
class Gear {
public:
template<typename Archive>
void serialize(Archive& ar, unsigned int version) { ar & v; }
void setV (const double& _v) { v = _v; }
double getV () { return v; }
void status () { std::cout << "v = " << v << std::endl; }
private:
double v;
};
class Car {
public:
template<typename Archive>
void serialize(Archive& ar, unsigned int version) {
ar & hp;
ar & x;
}
void setHP (const int& _hp) { hp = _hp; }
void setGear (Gear* _Gear) { x = _Gear; }
void status () { std::cout << "hp = " << hp << " Gear with v = " << x->getV() << std::endl; }
private:
int hp;
Gear *x;
};
int main() {
// Define new Gear:
Gear* g = new Gear();
g->setV(2.5);
g->status();
// Expectation is Car sets up the Gear.
Car c;
c.setHP(80);
c.setGear(g);
//c.status();
std::ofstream outputStream;
outputStream.open("bin.dat");
std::ostringstream oss;
boost::archive::binary_oarchive oa(outputStream);
oa & c;
outputStream.close();
Car b;
std::ifstream inputStream;
inputStream.open("bin.dat", std::ifstream::in);
boost::archive::binary_iarchive ia(inputStream);
ia & b;
b.status();
return 0;
}
So that works perfect, but I want to include the arma code (essentially) into the class. I tried to put the arma code within the class like such:
class Car {
public:
template<typename Archive>
void serialize(Archive& ar, unsigned int version) {
ar & hp;
ar & x;
}
namespace boost {
namespace serialization {
template<class Archive>
void save(Archive & ar, const arma::mat &t, unsigned int version)
{
ar & t.n_rows;
ar & t.n_cols;
const double *data = t.memptr();
for(int K=0; K<t.n_elem; ++K)
ar & data[K];
}
template<class Archive>
void load(Archive & ar, arma::mat &t, unsigned int version)
{
int rows, cols;
ar & rows;
ar & cols;
t.set_size(rows, cols);
double *data = t.memptr();
for(int K=0; K<t.n_elem; ++K)
ar & data[K];
}
} }
arma::mat A;// = arma::randu<arma::mat>(4,5);
void setHP (const int& _hp) { hp = _hp; }
void setGear (Gear* _Gear) { x = _Gear; }
void status () { std::cout << "hp = " << hp << " Gear with v = " << x->getV() << A<< std::endl; }
private:
int hp;
Gear *x;
};
And then in the int main():
Car c;
c.setHP(80);
c.setGear(g);
c.A = arma::randu<arma::mat>(4,5);
After trying to compile the attempt, I am getting the errors:
g++ -std=c++11 arma_serial_binary_versuch.cpp -larmadillo -lboost_serialization
arma_serial_binary_versuch.cpp:52:3: error: expected unqualified-id before ‘namespace’
namespace boost {
^
arma_serial_binary_versuch.cpp:121:1: error: expected ‘}’ at end of input
}
^
arma_serial_binary_versuch.cpp: In member function ‘void Car::serialize(Archive&, unsigned int)’:
arma_serial_binary_versuch.cpp:48:12: error: ‘hp’ was not declared in this scope
ar & hp;
^
arma_serial_binary_versuch.cpp:49:12: error: ‘x’ was not declared in this scope
ar & x;
^
arma_serial_binary_versuch.cpp: At global scope:
arma_serial_binary_versuch.cpp:50:5: error: expected unqualified-id at end of input
}
I've read that it's not possible to work with namespaces within a class but I am unsure of a workaround this. Anyone have any ideas/recommendations?
I've got a class that needs to become a singleton. All good and fine only that it has a non-default constructor, i.e. it takes three arguments.
The best I could come up with is, to set the constuctor private and then provide some kind of public "setup" function.
Are there any better solutions? My work around so far looks something like - any ideas to improve this are welcome!
#include <iostream>
class singltn {
private:
static singltn *instance;
int data;
// Private constructor so that no objects can be created.
singltn() {
data = 0;
}
int _AA;
int _BB;
int _CC;
public:
static singltn *getInstance() {
if (!instance)
instance = new singltn;
return instance;
}
void setup(int AA, int BB, int CC) {
_AA = AA;
_BB = BB;
_CC = CC;
}
int getData() {
return this->data;
}
void setData(int data) {
this -> data = data;
}
int getAA(){
return this->_AA;
}
};
//Initialize pointer to zero so that it can be initialized in first call to getInstance
singltn *singltn::instance = 0;
int main(){
singltn *a = a->getInstance();
a->setup(111,222,333);
std::cout << "dat " << a->getData() << " _AA " << a-> getAA() << std::endl;
a->setData(100);
std::cout << "dat " << a->getData() << " _AA " << a-> getAA() << std::endl;
singltn *b = b->getInstance();
std::cout << "dat " << b->getData() << " _AA " << a-> getAA() << std::endl;
return 0;
}
You can use a static factory/getter function that calls a private constructor. Something like this:
class Foo {
public:
static Foo& GetInstance() {
static Foo foo(param1, param2);
return foo;
}
private:
Foo(int a, int b) {
// ...
}
}
Of course, that requires your factory function to somehow know the parameters somehow.
Don't use real singleton (which handles creation + unique instance + global access), and adapt it:
class MyClass
{
private:
int data = 0;
int _AA;
int _BB;
int _CC;
static std::unique_ptr<MyClass> uniqueInstance;
MyClass(int AA, int BB, int CC) : _AA(AA), _BB(BB), _CC(CC) {}
MyClass(const MyClass&) = delete;
MyClass& operator =(const MyClass&) = delete;
public:
static void Create(int AA, int BB, int CC)
{
// if (uniqueInstance) throw std::runtime_error("Call it only once");
uniqueInstance = std::make_unique<MyClass>(AA, BB, CC);
}
static MyClass& GetInstance()
{
if (!uniqueInstance) throw std::runtime_error("Call Create before");
return *uniqueInstance;
}
int getData() const { return this->data; }
void setData(int data) { this->data = data; }
int getAA() const { return _AA; }
};
std::unique_ptr<MyClass> MyClass::uniqueInstance;
int main(){
MyClass::Create(111, 222, 333);
auto& a = MyClass::GetInstance();
std::cout << "dat " << a.getData() << " _AA " << a.getAA() << std::endl;
a.setData(100);
std::cout << "dat " << a.getData() << " _AA " << a.getAA() << std::endl;
}
Adapting Steve's Answer to provide a setup function for the singleton class:
class Foo {
public:
static Foo& GetInstance() { return SetupInstance(-1, -1); }
static Foo& SetupInstance(int a, int b) {
static Foo foo(a, b);
return foo;
}
private:
Foo(int a, int b) {
// ...
}
};
As the constructor of the static singleton get's only called once, multiple calls to SetupInstance will not re-create a new object of Foo, but always return the object which was created at the first call.
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 << ", ";
}
}
I'm trying to make a serialization of an object and then to deserialize it. Even though it seems that everything I wrote is ok I'm still getting an error during the deserialization.
int main(){
MapAttributes mapAtt(MAP_SIZE,MAP_SIZE);
initMapFromImage("map1.png",&mapAtt);
int prevxMax = mapAtt.prevxMax ;
int prevyMax = mapAtt.prevyMax ;
int prevxMin = mapAtt.prevxMin ;
int prevyMin = mapAtt.prevyMin ;
PixelCoords pose = PixelCoords(mapAtt.robotPose.dx, mapAtt.robotPose.dy);
PixelCoords target = PixelCoords( 2048+250, 2048+250 );
PartitionGraphNodes partitionGraph(&mapAtt);
PartitionGraphNodes partitionGraph2(&mapAtt);
partitionGraph.createIncrementalPartition(pose,target);
if (partitionGraph.nodes.size()!=0){
saveSerializedObject<PartitionGraphNodes(partitionGraph,"partition_graph_marshall");
std::cout << "size= " << partitionGraph.nodes.size() << "\n";
restoreSerializedObject<PartitionGraphNodes>(partitionGraph2,"partition_graph_marshall");
}
else{
std::cout << "RUN FOR YOUR LIVES!!!\n";
}
return 0;
This is my code where I'm trying to get my objects serialized and deserialized.
Here is the function for the serialization and the deserialization:
template<class T>
void saveSerializedObject(const T &s, const char * filename){
// make an archive
std::ofstream ofs(filename);
boost::archive::text_oarchive oa(ofs);
oa << s;
}
template<class T>
void restoreSerializedObject(T &s, const char * filename)
{
// open the archive
std::ifstream ifs(filename);
if (ifs.good()) {
std::cout << "Coming!!!\n";
boost::archive::text_iarchive ia(ifs);
ia >> s;
} else {
// throw an error or something
assert(false);
}
}
Finally I have wrote the code for the serialization exactly as the Boost documentation suggests, but I still get an error: an instance of 'boost::archive::archive_exception' what(): input stream error. Can you help me with that?
EDIT:
As it is clear enough, initially I'm trying to serialize an object of class PartitionGraphNodes. So this is how an PartitionGraphNodes object is serialized:
#include <boost/serialization/base_object.hpp>
class PartitionGraphNodes: public NodesVector{
private:
std::vector<int> targetNeighbors; //!<Vector holding target neighbors
std::vector<int> robotNeighbors; //!<Vector holding robot neighbors
std::vector<PixelCoords> uniformPartition;
public:
PartitionGraphNodes(MapAttributes* mapAttr);
void createIncrementalPartition(PixelCoords startPos, PixelCoords target);
int insertNodeInPartition(Node currNode);
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
std::cout << "In partition_serial" << "\n";
ar & boost::serialization::base_object<NodesVector>(*this);
}
};
#include <boost/serialization/vector.hpp>
class NodesVector{
protected:
//~ std::vector<Voronode> nodes;
public:
NodesVector(void){};
std::vector<Node> nodes;
MapAttributes* mapAttributes;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
std::cout << "In nodesVector_serial" << "\n";
ar & nodes;
}
};
#include <boost/serialization/vector.hpp>
class Node{
public:
PixelCoords p; //!< The coordinates of the node
bool visited; //!< True if the node has been visited
unsigned int ID; //!< The node's ID
int parent;
std::vector<PixelCoords> neigh; //!< Vector of the neighbors of the node (coords)
std::vector<unsigned int> neighID; //!< Vector of the neighbors' IDs
std::vector<float> dist; //!< Vector of the distances of the neighbors
Weight w; //!< The node's weight
std::vector<PixelCoords> path;
Node(PixelCoords a) {p=a;}
Node(PixelCoords a,unsigned int IDt) {p=a; ID=IDt;}
Node(void){}
void makeNeighbor(Node &a);
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
std::cout << "In nodes_serial" << "\n";
ar & p;
ar & visited;
ar & ID;
ar & parent;
ar & neigh;
ar & neighID;
ar & dist;
ar & w;
}
};
#endif
I think you need
BOOST_CLASS_EXPORT();
lines.
See for instance the answers to this question: Where to put BOOST_CLASS_EXPORT for boost::serialization?