Question

I need to create a vector of ODESolver objects. If I create an ODESolver object, everything is fine, however, if I use a vector I get a segmentation fault when the ODESolver constructor is called. Why is this the case and how do I solve this problem?

#include <vector>
#include <iostream>    
#include <gsl/gsl_errno.h>
#include <gsl/gsl_odeiv.h>
#include <gsl/gsl_matrix.h>

struct ODESystem {};

struct ODESolver {
    ODESolver(ODESystem &ODE_system)
    {
        d_solver_ptr  = gsl_odeiv_step_rkf45;
        d_step_ptr    = gsl_odeiv_step_alloc(d_solver_ptr, d_dim_ODE);
        d_evolve_ptr  = gsl_odeiv_evolve_alloc(d_dim_ODE);
    }

    ~ODESolver()
    {
        gsl_odeiv_step_free(d_step_ptr);
        gsl_odeiv_evolve_free(d_evolve_ptr);
    }

    const gsl_odeiv_step_type *d_solver_ptr;
    gsl_odeiv_step *d_step_ptr;
    gsl_odeiv_evolve *d_evolve_ptr;
    gsl_odeiv_system d_ODE_system;
    const static int d_dim_ODE = 4;
};

struct MyODESystem : public ODESystem {};

int main()
{
    MyODESystem myODE;
    ODESolver mySolver(myODE);                      // WORKS FINE

    std::vector<MyODESystem> myODEVec;
    myODEVec.push_back(MyODESystem());

    std::vector<ODESolver> mySolverVec;
    mySolverVec.push_back(ODESolver(myODEVec[0]));  // SEGMENTATION FAULT: 11

    return 0;
}
Was it helpful?

Solution

I'm guessing gsl_odeiv_step_alloc and gsl_odeiv_step_free are similar to malloc and free. In this case it's clear that you have a problem of "double free". In the following code

mySolverVec.push_back(ODESolver(myODEVec[0]));

you create a temporary ODESolver object which allocates some memory and assigns it to the member variables d_step_ptr and d_evolve_ptr. The the object is copied with the default copy constructor which just does memcpy (copies bits) into the vector. The the temporary object is destroyed and the memory is freed. When the vector mySolverVec goes out of scope it destroys all objects inside of it. Which tries to free the same memory again and you most likely have a crash!

You should either prohibit copying of your object. In C++11 you could allow only moves and no copies. If you have to stick with the older standard then some reference counting scheme would make sense. Take a look at boost library and specifically boost::shared_ptr.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top