当我有复杂的类(例如,实现一些数值算法,如偏微分方程求解器)时,我经常遇到这样的情况,它可以根据用例拥有或从外部上下文绑定数据数组。问题是如何为此类创建健壮的析构函数。简单的方法是制作布尔标志,指示数组是否拥有。例如
// simplest example I can think about
class Solver{
int nParticles;
bool own_position;
bool own_velocity;
double* position;
double* velocity;
// there is more buffers like this, not just position and velocity, but e.g. mass, force, pressure etc. each of which can be either owned or binded externally independently of each other, therefore if there is 6 buffers, there is 2^6 variants of owership (e.g. of construction/destruction)
void move(double dt){ for(int i=0; i<n; i++){ position[i]+=velocity[i]*dt; } }
~Solver(){
if(own_position) delete [] position;
if(own_velocity) delete [] velocity;
}
};
自然地,这促使我们围绕数组指针创建一个模板包装器(我应该称之为智能指针吗?):
template<typename T>
struct Data{
bool own;
T* data;
~Data{ if(own)delete [] T; }
};
class Solver{
int nParticles;
Data<double> position;
Data<double> velocity;
void move(double dt){ for(int i=0; i<n; i++){ position.data[i]+=velocity.data[i]*dt; } }
// default destructor is just fine (?)
};
问题:
- 这一定是常见的模式,我在这里重新发明轮子吗?
- 在 C++ 标准库中有这样的东西吗?(对不起,我更像是物理学家而不是程序员)
- 有什么需要考虑的问题吗?
--------------------------------------
编辑:为了明确什么bind to external contex
意思(正如 Albjenow 建议的那样):
案例 1)私有/内部工作数组(无共享所有权)
// constructor to allocate own data
Data::Data(int n){
data = new double[n];
own = true;
}
Solver::Solver(int n_){
n=n_;
position(n); // type Data<double>
velocity(n);
}
void flowFieldFunction(int n, double* position, double* velocity ){
for(int i=0;i<n;i++){
velocity[i] = sin( position[i] );
}
}
int main(){
Solver solver(100000); // Solver allocates all arrays internally
// --- run simulation
// int niters=10;
for(int i=0;i<niters;i++){
flowFieldFunction(solver.n,solver.data.position,solver.data.velocity);
solver.move(dt);
}
}
案例2)绑定到外部数据数组(例如来自其他类)
Data::bind(double* data_){
data=data_;
own=false;
}
// example of "other class" which owns data; we have no control of it
class FlowField{
int n;
double* position;
void getVelocity(double* velocity){
for(int i=0;i<n;i++){
velocity[i] = sin( position[i] );
}
}
FlowField(int n_){n=n_;position=new double[n];}
~FlowField(){delete [] position;}
}
int main(){
FlowField field(100000);
Solver solver; // default constructor, no allocation
// allocate some
solver.n=field.n;
solver.velocity(solver.n);
// bind others
solver.position.bind( field.position );
// --- run simulation
// int niters=10;
for(int i=0;i<niters;i++){
field.getVelocity(solver.velocity);
solver.move(dt);
}
}