TheIdealis
TheIdealis

Reputation: 727

Destructor calls during integration with boost odeint

If I integrate a system with boosts odeint module, using a class to define the derivative, the destructor of this class is called very often.

  1. Is this behavior intended?
  2. Why is it the case?
  3. What should I do if I want to allocate arrays dynamically in this class?

For example, this code:

#include <iostream>
#include <boost/numeric/odeint.hpp>

using namespace std;
using namespace boost::numeric::odeint;

class foo
{
public:
    virtual ~foo() {
        std::cout << "destructor called" << std::endl;
    }

    void operator()(const double &x, double &dxdt, double t) const    {
        dxdt = 1;
    }
};

int main( int argc , char **argv )
{
    double x = 0;
    const double dt = 0.1;
    typedef runge_kutta4< double > stepper_type;

    integrate_const( stepper_type() , foo(), x , 0.0 , 10.0 , dt);

    return 0;
}

calls the destructor around 400 times. (I'am a beginner in c++)

Upvotes: 3

Views: 136

Answers (2)

RHertel
RHertel

Reputation: 23818

The destructor is only called once at the end of the program if

  1. there is an instantiation of foo in main and
  2. if std::ref() is used in the call to integrate_const()

Like this:

#include <iostream>
#include <boost/numeric/odeint.hpp>
#include <functional>

using namespace boost::numeric::odeint;

class foo
{
public:
    virtual ~foo() {
        std::cout << "destructor called" << std::endl;
    }

    void operator()(const double &x, double &dxdt, double t) const   {
        dxdt = 1;
    }
};

int main( int argc , char **argv )
{
    double x = 0;
    const double dt = 0.1;
    typedef runge_kutta4< double > stepper_type;
    foo myfoo;
    integrate_const( stepper_type() , std::ref( myfoo ), x , 0.0 , 10.0 , dt);
    return 0;
}

You can allocate any kind of data dynamically in the foo class, for instance by adding a simple setter function .setData() that could be called from main with

myfoo.setData(myArray);

prior to the call to integrate_const().

Upvotes: 1

Ferenc Deak
Ferenc Deak

Reputation: 35458

Simple: just trace back the calls in a debugger to your destructor.

You will see that the first level is:

template<class Stepper, class System, class State, class Time> size_t integrate_const( Stepper stepper, System system, State &start_state, Time start_time, Time end_time, Time dt)

which after several intermediary steps has a loop in it:

while( less_eq_with_sign( static_cast<Time>(time+dt) , end_time , dt ) ) { obs( start_state , time ); st.do_step( system , start_state , time , dt ); ...

found in usr/include/boost/numeric/odeint/integrate/detail/integrate_const.hpp:59

and unfortunately all the parameters are being sent down via value, not reference in the boost code. So it will create and destroy a lot of temporary objects based from the one you have created.

If you want to allocate arrays dynamically I would recommend to use std::vector because approaching this issue via C style arrays will take a lot of time to debug.

Upvotes: 1

Related Questions