0

I'm using the example provided with Boost.MPI documentation found here. I have a bit modified these two classes and as soon as I add destructor to this class, I will get segmentation fault during receiving a std::vector<drivedClass>. How can I resolve this? This class doesn't have any pointer and everything is defined statically, so default destructor is fine. I'm compiling this with : mpic++ mpidatatype.cpp -o out -lboost_mpi -lboost_serialization The example is :

#include <boost/mpi.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
using namespace boost::archive;
std::stringstream ss;

class animal
{
private:
    friend class boost::serialization::access;
    template <typename Archive>
    void serialize(Archive &ar, const unsigned int version) {
         ar & legs_;
         ar& arms_;
        }
protected:
    int legs_;
    int arms_;
public:
    animal() = default;
    animal(const int legs) : legs_{legs},arms_{2} {}
    int legs() const { return legs_; }
    virtual void printName() = 0;
    virtual ~animal()=default; 

};
class bird : public animal
{
public:
    bird() = default;
    bird(int legs, bool can_fly) :
    animal{legs}, can_fly_{can_fly} {}
    bool can_fly() const { return can_fly_; }
    void printName() {
        std::cout<<"My name is bird"<<std::endl; 
    };
    virtual ~bird()=default;
private:
    friend class boost::serialization::access;
    template <typename Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & boost::serialization::base_object<animal>(*this);
    ar & can_fly_;
    }
    bool can_fly_;
};
namespace boost { namespace mpi {
    template <>
    struct is_mpi_datatype<bird> : mpl::true_ {};
}}

int main(int argc, char* argv[])
{
    boost::mpi::environment env;
    boost::mpi::communicator world;
    bool isBirdMPIType =boost:: mpi::is_mpi_datatype<bird>::value;
    std::cout << "Is bird a valid MPI datatype? " << std::boolalpha << isBirdMPIType << std::endl;

    if (world.size() > 1)
    {
        if (world.rank() == 0)
        {


            //std::vector<bird> dummy ={bird (1,0)};
            std::vector<bird> dummy ={bird (1,0), bird(2,1)};
            world.send(1, 0, dummy);
            
        }
        if (world.rank() == 1)
        {
            std::vector<bird> dummy(2, bird(1,1)); 
           // std::vector<bird> dummy(1, bird(1,1)); 
            world.recv(0, 0, dummy);
        }
    }
}

I have provided this example as a demo. In the real code that I have, I don't have any pointer as member class and destructors are all default, it took me hours to figure out destructor of the class was the cause of segmentation fault. Questions about this all revolved around having a pointer and not handling that correctly in destructor but when the class doesn't have any, why this should be a problem?

MA19
  • 510
  • 3
  • 15
  • There's no polymorphism in your code, you don't need the destructors to begin with, and definitely not virtual destructors. – Some programmer dude May 28 '23 at 15:36
  • I'm not sure, are you saying "destructors are all default" cause segment fault, or adding destructor ("having class destructor") cause it? – apple apple May 28 '23 at 15:59
  • @Someprogrammerdude I have simplified the problem in order to post it short. In real code that I'm working on, I have polymorphism, and so I need virtual destructors and as I tested despite having polymorphism, commenting virtual destructors resolved the segmentation fault. – MA19 May 28 '23 at 16:00
  • @appleapple I have not tested for non default destructors since my problem only requires default ones. – MA19 May 28 '23 at 16:02
  • @MA19 I mean, the title is a little contradict with the body (and the example). I think it's helpful to clarify it's 1. having (implicitly generated) default destructor 2. having `=default` destructor 3. have user-defined destructor (possibly empty) cause the problem. – apple apple May 28 '23 at 16:04
  • If you have polymorphism, then please make a more relevant [mre]. Using actual polymorphic functions, and storing pointers to the polymorphic objects in your containers (using pointers to the base class). – Some programmer dude May 28 '23 at 16:11
  • @Someprogrammerdude I don't understand why should I need to store pointers to my objects in my container. – MA19 May 28 '23 at 16:21
  • @Someprogrammerdude Okay, I added polymorphism. – MA19 May 28 '23 at 16:25
  • Polymorphism requires pointers or references to the base class. Otherwise if you have the actual child-class object, there's just no point with the virtual functions. So your example *still* isn't polymorphic. – Some programmer dude May 28 '23 at 16:31
  • @Someprogrammerdude the point here is not whether I need virtual or not. Having that is not wrong here, but it causes problems that I need explanation for that. – MA19 May 28 '23 at 16:38
  • I'm really sorry, but with your original example, the simple solution was to just remove the destructor from the code. And since your current example doesn't use polymorphism, the simple solution is to remove all virtual functions (or at least make them non-virtual), and *then* remove the destructors. Iif you continue to read the examples in the serialization page you link to, then you would see them using pointers in their virtual examples, and more importantly use `register_type` to be able to properly handle the pointers. – Some programmer dude May 28 '23 at 17:48
  • So please try to base your example on the *last* example in the linked page, with pointers and `register_type`. If that works well with MPI then the problem was that your example was flawed and incomplete. If it doesn't work, then perhaps it's just not possible with truly polymorphic classes to be passed over the (basically) C MPI interface. (And note that there doesn't seem to be any polymorphic examples or mentions in the Boost MPI documentation, at least not that I could find.) – Some programmer dude May 28 '23 at 17:50
  • Also, to make it much simpler, don't involve containers. Make it work for a single (and properly polymorphic) `bird` object (though a pointer to `animal`). If you can't even pass that through MPI, then there's really no reason to begin trying with containers. Perhaps even simpler, just an instance of `animal` (through a pointer), before trying with `bird`? – Some programmer dude May 28 '23 at 18:04
  • @Someprogrammerdude I need to keep them as virtual, and I am aware of simple solution, but that doesn't work for me and I need to know what is happening there. – MA19 May 28 '23 at 18:05
  • 1
    @Someprogrammerdude I can pass one object without segmentation fault with having everything virtual but not two objects in std::vector and for my application, I need to pass a vector of objects, so I need to resolve this issue. – MA19 May 28 '23 at 18:08
  • Please update your question with the last information, that is kind of crucial. And unless this is only for curiosity (which you should also state in the question in that case), please try to tell us as much as possible about the *actual* and *underlying* problem you need to solve. Why do you need to pass containers of polymorphic objects? What is the requirement for using MPI? That will make it less of an [XY problem](https://en.wikipedia.org/wiki/XY_problem), and might help us find better suited solutions for your actual problem. – Some programmer dude May 28 '23 at 18:47
  • 1) The posted code is missing a required `#include ` 2) If you ever attempt to serialize polymorphically, Boost.Serialization requires that you register the child classes in question. – Avi Berger May 28 '23 at 21:03
  • @AviBerger I updated the code to include the header you mentioned but still I have the problem. Also, I have incuded a test for child class to see whether it's a mpi type or not and it returns true. So, What should I register if MPI takes bird as a type ? – MA19 May 29 '23 at 00:49
  • 1
    "Why does virtual destructor cause segmentaion fault ..." - The presence of a `virtual` destructor does not *cause* a segmentation fault (unless you are doing something *really* weird - which you should probably then stop doing) - there's something else wrong with your code. – Jesper Juhl May 29 '23 at 01:21
  • 1
    "`virtual ~bird(){};`" - Why a user-defined destructor? That makes your class non-trivial (even if it is empty). `virtual ~bird() = default;` should do here. Or just leave out the destructor entirely and let the compiler synthesize it. – Jesper Juhl May 29 '23 at 01:25
  • I was betting on the include. Oh. well. The page you linked shows 2 different ways to register bird. That is only needed if you attempt to serialize polymorphically, though. As @JesperJuhl, indicates, a virtual destructor would not be the cause, though it might impact the appearance of symptoms from a bug. – Avi Berger May 29 '23 at 01:41
  • I understand the presence of destructor should not cause this since as you all said I'm not doing anything there, but the weird thing is why just commenting out destructor eliminates segmentation fault? – MA19 May 29 '23 at 02:01
  • @JesperJuhl Okay I updated the question to have default destructor. – MA19 May 29 '23 at 02:06

0 Answers0