I've a class that one of its members is a pointer to a 2d array of integers. I want to pass this member in serialize function, but I'm getting this error:
error: request for member ‘serialize’ in ‘t’, which is of non-class type ‘int’
I read the documentation and I have found that they have used
ar.register_type(static_cast<type *>(NULL));
so I did the same thing, but still I have a problem.
I'm attaching the piece of code that I'm trying to serialize:
#include <iostream>
#include<set>
#include<map>
#include <boost/mpi/datatype.hpp>
#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <boost/mpi.hpp>
class Dummy
{
private:
int m_N;
int** array;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int /*version*/)
{
ar &m_N;
ar.register_type(static_cast<int**>(NULL));
ar &array;
}
public:
Dummy(){};
Dummy(const int N)
{
m_N=N;
array = new int*[N+1];
for(auto i=0;i<N+1;i++)
{
array[i] = new int[N+1];
}
};
~Dummy()
{
for(auto i=0;i<m_N+1;i++)
{
delete[]array[i];
}delete[]array;
};
};
namespace boost { namespace mpi {
template <>
struct is_mpi_datatype<Dummy> : mpl::true_ { };
} }
int main(int argc, char* const argv[])
{
boost::mpi::environment env;
boost::mpi::communicator world;
std::map<int,std::vector<Dummy>> IdToVecObject;
std::vector<Dummy> vec;
std::set<int> neigbours;
if(world.rank()==0)
{
Dummy obj(1);
vec.push_back(obj);
neigbours.insert(1);
IdToVecObject.emplace(1,vec);
}
if(world.rank()==1)
{
Dummy obj(1);
vec.push_back(obj);
neigbours.insert(0);
IdToVecObject.emplace(0,vec);
}
for(auto it:IdToVecObject)
{
int target= it.first;
Dummy obj(1);
world.send(target,0,obj);
}
for(auto i:neigbours)
{
int source= i ;
Dummy obj(1);
std::vector<Dummy> objects;
world.recv(source,0,obj);
}
return 0;
}
Your array is not a 2-dimensional array. At most it could be described as a "regular" jagged array.
register_type
relates only to types in a polymorphic type hierarchy, so that's completely unrelated to C arrays, or int
for that matter.
You need to serialize the elements. The simplest way to do it:
template <class Archive> void serialize(Archive& ar, unsigned) {
ar& m_N;
for (int i = 0; i<m_N; ++i)
ar& boost::serialization::make_array(array[i], m_N);
}
I forgot to manually manage the allocations - which is exactly why you don't use C arrays:
class Dummy {
private:
int m_N = 0;
int** m_array = nullptr;
friend class boost::serialization::access;
template <class Archive> void serialize(Archive& ar, unsigned) {
if /*constexpr*/ (Archive::is_saving) {
ar& m_N;
} else {
int curN = m_N;
ar& m_N;
if (m_N > curN) // keep old allocation if big enough, optionally
init();
}
for (auto* el : m_array)
ar & boost::serialization::make_array(el, m_N);
}
void init() {
if (m_array)
destroy();
m_array = new int*[m_N + 1];
for (auto& el : m_array)
el = new int[m_N + 1];
}
void destroy() {
for (auto& el : m_array)
delete[] el;
delete[] m_array;
m_array = nullptr;
}
public:
Dummy(int N = 0) : m_N(N){ init(); };
~Dummy() { destroy(); };
};
(you may need to #include <boost/serialization/array_wrapper.hpp>
).
The much saner way to do it, would be to actually use a multidimensional array: https://stackoverflow.com/a/62109089/85371 or at least store them contiguously like int[N][M]
or even simpler int[N*M]
.