我正在尝试构建一个由de_solver
类编码的通用随机微分方程求解器,它采用由model
类给出的一组微分方程。该模型通过类sde
提供给求解器,该类在模型和求解器之间进行接口,在确定性+随机方程的两个子集中重构原始模型的方程。
目前我的代码存在一些问题,我认为必须处理继承和类型转换。特别是我无法将指定模型方程的成员函数传递给积分器。首先说我有这种类型的model
类:
class model{
...
public:
size_t N_eq;
model(...); // Assign N_eq and parameters and other stuff
...
int equations_det(double t, const double y_[], double dy_[]); // Define deterministic RHS of equations
static int equations_gsl_wrapper(double t, const double y_[], double dy_[],void *params); // A wrapper that make equations_det suitable for a GSL solver
void equations_stoch(double t,double dt,const double y_[], double dy_[],); // The stochastic RHS of the model equations
static void ode_s_wrapper(double t,const double y_[], double dy_[], void *params); // A wrapper to pass equations_det to the stochastic integrator (in the class `de_solver`).
int simulate(t,tfin,tstep); // The actual simulator which will invoke the 'de_solver'
};
如in this post指出的那样,static
规范需要使用GSL积分器作为模型的确定性部分。
然后,接口类sde
就是:
class sde{
...
public:
size_t N_eq;
sde(size_t N_,
int (*dtr)(double, const double*, double*, void*),
void (*stc)(double, double, const double*, double*, void*));
int (*deterministic)(double t, const double* y_[], double* dy_[], void * params);
void (*stochastic)(double t,const double y_[], double dy_[], void *params);
//Then again, akin to the model class, use some `wrappers`
static int deterministic_wrapper(double t, const double y_[], double dy_[], void * params);
static void stochastic_wrapper(double t, const double y_[], double *dy_, void *params);
};
我们的想法是在sde
类中包含从给定的任何模型继承的成员函数。至于两个包装纸,'我将简要介绍一下我很快介绍它们的原因。
最后,de_solver
类是这样的:
class de_solver{
sde *sys;
public:
de_solver(sde *system); // Will initialize solver with the system put in the `sde` form
...
void integrate(void *params, double *ts, double **sol);
};
model
在单独的文件(model.H
和model.CPP
)中声明/定义sde
和de_solver
solvers.h
和{ {1}})。
我们的想法是在solvers.cpp
类中拥有simulate
成员函数,以便
model
总之,int model::simulate(double t, double tfin, double dt){
// Prepare solver
// 1. Create the `sde` object from model `sys`
sde recast_sys(NEQ, model::deterministic_wrapper, model::stochastic_wrapper);
// 2. Instantiate solver with recast system
de_solver integrator(&recast_sys);
// Run simulation
double *ts = ... // Output time instants
double **sol = ... // Output solution
void *params_base = static_cast<void*>(std::addressof(this));
integrator.integrate(params_base);
return 1; // In practice there is some error check on this return condition (omitted here for brevity)
}
调用sys
,它适用于integrator
提供的模型方程的确定性和随机部分。因为积分器的确定性部分依赖于GSL求解器,所以我使用附加参数参数将指向解算器的指针传递给实际的类成员函数。以这种方式,在recast_sys
成员函数内部(见above mentioned post)
integrator.integrate
从this post获取了一个指向空洞的两个指针的数组。但是,似乎曾经在包装器中使用它,它产生错误可能是因为void数组上的算术不清楚(如指出here)?
目前我无法针对上面报告的错误编译我的代码。也出于某种原因,编译器告诉我de_solver::integrate(void *params_base, ...){
...
// I allocate an array of two void pointers: the first to the `model` class (assumed to be passed by `params_base`), and the second to the `sde` class
void **params = (void**)calloc(2,sizeof(void*));
params[0] = params_base;
params[1] = reinterpret_cast<void *>(std::addressof(sys)); // the recast system as private member of the sde class
gsl_odeiv2_driver * d;
gsl_odeiv2_system system = {sys->deterministic_wrapper, nullptr, sys->NEQ, params};
d = gsl_odeiv2_driver_alloc_y_new (&system, gsl_odeiv2_step_bsimp, opts.dt, opts.atol, opts.rtol);
...
}
int sde::deterministic_wrapper(double t, const double y_[], double dy_[], void * params){
assert(params);
return(static_cast<sde*>(params[1])->deterministic(t,y_,dy_,params)); // This will issue an error: ‘void*’ is not a pointer-to-object type
}
int model::equations_gsl_wrapper(double t, const double y_[], double dy_[], void * params){
assert(params);
return(static_cast<model*>(params[0])->ode_gsl(t,y_,dy_)); // This will issue an error: ‘void*’ is not a pointer-to-object type
}
成员函数中的this
指针生成
model.simulate
我怀疑我正在搞乱静态和非静态成员函数,而我没有正确地传递它们。任何输入将不胜感激。
答案 0 :(得分:0)
我还没有完全掌握你的整个问题,但答案似乎很简单:
错误:使用已删除的函数'const _Tp * std :: addressof(const _Tp&amp;&amp;)[with _Tp = model *]'
编译器告诉您正在尝试将指针的地址带到您的实例,因为您执行了std::addressof(this)
。 this
已经 您要查找的指针(model*
),直接将其投放到void*
。
return(static_cast<model*>(params[0])->ode_gsl(t,y_,dy_)); // This will issue an error: ‘void*’ is not a pointer-to-object type
当您执行params[0]
时,您已经取消引用指针一次(内置的x[y]
完全等同于*(x + y)
)并最终得到一个普通的void
,其中编译器不喜欢。你的数组的void指针有另一个间接层:
int deterministic_wrapper(double t, /* ... */ void * params) {
void** voidPtrs = static_cast<void**>(params);
return static_cast<sde*>(voidPtrs[1])->deterministic(t, /* ... */ params);
}
请参阅here。
更好的解决方案是创建一个struct
来保存指向你的类的指针(你的虚拟指针数组基本上就是那个,距离three star programming足够接近你犯了上面的错误):
struct myParams
{
model* _model;
sde* _sde;
};
// ...
int deterministic_wrapper(double t, /* ... */ void * params) {
return static_cast<myParams*>(params)->_sde->deterministic(t, /* ... */ params);
}
请注意,无论如何,您都必须清理内存。如果您分配了该阵列,则需要将其释放,如果您new
需要delete
它所需的结构,并且如果您在堆栈上创建它,则需要确保它长寿命足以让所有这些功能完成。
答案 1 :(得分:0)
感谢Max Langhof的建议,代码现在运行正常。我提到的可见性问题与类方法地址的错误传递有关。
在上面的代码示例中,我在model::simulate
方法中初始化了sde recast_sys
// Prepare solver
// 1. Create the `sde` object from model `sys`
sde recast_sys(NEQ, model::deterministic_wrapper, model::stochastic_wrapper);
而是传递::*_wrapper
函数地址的正确方法是this
指针,即
sde recast_sys(NEQ, this->deterministic_wrapper, this->stochastic_wrapper);