【问题标题】:Destructor calls during integration with boost odeint与 boost odeint 集成期间的析构函数调用
【发布时间】:2020-02-20 16:54:08
【问题描述】:

如果我将一个系统与 boosts odeint 模块集成在一起,使用一个类来定义派生类,那么这个类的析构函数会被非常频繁地调用。

  1. 这种行为是有意的吗?
  2. 为什么会这样?
  3. 如果我想在这个类中动态分配数组怎么办?

例如这段代码:

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

调用析构函数大约 400 次。 (我是 C++ 初学者)

【问题讨论】:

  • @Someprogrammerdude 不,integrate_const 是一个模板函数(在 boost 1.71.0 中)。
  • 查看文档显示integrate_const 是一个带有模板参数System [=foo] 的函数。该参数被复制多次——实际上在每个迭代步骤中复制了 4 次,因为它是 100 次迭代的经典龙格-库塔方法。如果您必须在 foo 中存储一些额外的数据,我建议您使用指针语义围绕该数据构建一个瘦包装器。
  • @Albjenow 那将是一个很好的答案。
  • 你的问题很好!!!如果在这里有同样的效果,但直到你的问题我才意识到。

标签: c++ boost odeint


【解决方案1】:

析构函数只在程序结束时调用一次,如果

  1. 在 main 和
  2. 中有一个 foo 的实例化
  3. 如果在对integrate_const() 的调用中使用了std::ref()

像这样:

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

您可以在 foo 类中动态分配任何类型的数据,例如通过添加一个简单的 setter 函数 .setData() 可以从 main 调用

myfoo.setData(myArray);

在致电integrate_const()之前。

【讨论】:

  • 感谢您使用std::ref。备注:如果方程系统是 const,则可以使用 std::cref。
【解决方案2】:

简单:只需将调试器中的调用追溯到您的析构函数。

你会看到第一层是:

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)

经过几个中间步骤后有一个循环:

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 ); ...

发现于usr/include/boost/numeric/odeint/integrate/detail/integrate_const.hpp:59

不幸的是,所有参数都是通过值发送的,而不是在 boost 代码中的引用。因此,它会根据您创建的对象创建和销毁大量临时对象。

如果您想动态分配数组,我建议您使用std::vector,因为通过 C 样式数组解决此问题需要大量时间来调试。

【讨论】:

  • 非常感谢您的回答。我将 RHertel 标记为正确的,因为它直接解决了我的主要问题,但你的也确实很有帮助。切换到 std::vector 是一个好点。我之前看过代码,但我还不能相信我对它的理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
  • 2012-12-12
  • 2011-05-29
相关资源
最近更新 更多