【发布时间】:2020-03-28 03:28:17
【问题描述】:
当我有复杂的类(例如,实现一些数值算法,如偏微分方程求解器)时,我经常遇到这样的情况,它可以根据用例拥有或从外部上下文绑定。问题是如何为此类创建健壮的析构函数。简单的方法是制作布尔标志,指示数组是否拥有。例如
// 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);
}
}
【问题讨论】:
-
一个
std::shared_ptr? -
从技术上讲,您可以将
std::unique_ptr或std::shared_ptr与自定义删除器一起使用,该删除器存储是删除(您拥有它)还是什么都不做(外部拥有)。编写自己的课程也很有效,但要在各个方面做到正确需要一些经验...... -
还有提升intrusive_ptr
-
你能举一个“从外部上下文绑定”的例子吗?在不了解您的用例的情况下,我们很难提出解决方案。
-
UniversE > “其他实例”不必知道。如果数据数组为
own=True所拥有,则根本不应从外部访问该数组(或者如果由用户负责处理该问题)。这不是这里的任务。这里的任务是创建可以分配自己的工作数组或绑定到已经存在的工作数组的类。
标签: c++ destructor smart-pointers ownership