我经常遇到这样的情况:当我有一个复杂的类(例如实现一些数值算法,比如偏微分方程求解器),其中包含数据数组,这些数组可以根据使用情况要么由该类自己拥有,要么从外部上下文中绑定。问题在于如何为这样的类创建一个强大的析构函数。简单的方法是创建一个布尔标志,指示数组是否被拥有。例如:
// 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++标准库中是否有类似的东西?(抱歉,我更像一个物理学家而不是一个程序员)
- 有什么需要考虑的要点吗?
----------------------------------------
编辑:为了阐明绑定到外部上下文
的含义(如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);
}
}
std::shared_ptr
? - tkauslstd::unique_ptr
或std::shared_ptr
,该删除器存储是否删除(您拥有它)或不执行任何操作(由外部拥有)。编写自己的类也可以,但在各个方面正确地完成需要一些经验... - Max Langhofown=True
,那么该数组根本不应从外部访问(或者如果它被访问了,用户有责任处理这个问题)。这不是这里的任务。这里的任务是创建一个类,可以分配自己的工作数组,或绑定到已经存在的工作数组上。 - Prokop Hapala