Search code examples
c++serializationboostdeserializationmpi

Serialization of pointer to a 2d array as a member of a class using Boost.MPI


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; 
}

Solution

  • 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);
    }
    

    WHOOPS

    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].