gpt4 book ai didi

c++ - 可以在运行时更改所有权的智能指针 (C++)

转载 作者:行者123 更新时间:2023-12-02 00:10:50 24 4
gpt4 key购买 nike

我经常遇到这样的情况:当我有复杂的类(例如,实现一些数值算法,如偏微分方程求解器)时,它可以根据用例拥有或从外部上下文绑定(bind)数据数组。问题是如何为此类创建健壮的析构函数。简单的方法是创建 bool 标志来指示数组是否被拥有。例如

// 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)到外部上下文的含义(如Albjenow建议的那样):

情况 1) 私有(private)/内部工作数组(无共享所有权)


// 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) 绑定(bind)到外部数据数组(例如来自其他类)

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

最佳答案

这是一种简单的方法,可以做你想做的事情,而无需自己编写任何智能指针(很难获得正确的细节)或编写自定义析构函数(这意味着来自其他人的更多代码和潜在错误) rule of five 所需的特殊成员函数):

#include <memory>

template<typename T>
class DataHolder
{
public:
DataHolder(T* externallyOwned)
: _ownedData(nullptr)
, _data(externallyOwned)
{
}

DataHolder(std::size_t allocSize)
: _ownedData(new T[allocSize])
, _data(_ownedData.get())
{
}

T* get() // could add a const overload
{
return _data;
}

private:
// Order of these two is important for the second constructor!
std::unique_ptr<T[]> _ownedData;
T* _data;
};

https://godbolt.org/z/T4cgyy

unique_ptr成员保存自分配的数据,或者在使用外部拥有的数据时为空。原始指针指向 unique_ptr前一种情况是内容,后一种情况是外部内容。您可以修改构造函数(或者仅通过静态成员函数访问它们,例如 DataHolder::fromExternal()DataHolder::allocateSelf(),它们返回使用适当的构造函数创建的 DataHolder 实例),以防止意外误用。

(请注意,成员按照在类中声明的顺序进行初始化,而不是按照成员初始值设定项列表的顺序进行初始化,因此在原始指针之前添加 unique_ptr 非常重要!)

当然,此类无法复制(由于 unique_ptr 成员),但可以移动构造或分配(使用正确的语义)。开箱即用,应有尽有。

关于c++ - 可以在运行时更改所有权的智能指针 (C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59157194/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com