C++ C+中原始指针的智能向量+;11?
我使用的是一个旧的开源库,其中包含以下(简化的)API:C++ C+中原始指针的智能向量+;11?,c++,c++11,smart-pointers,C++,C++11,Smart Pointers,我使用的是一个旧的开源库,其中包含以下(简化的)API: // some class that holds a raw pointer to memory on the heap // DOES NOT delete it in its destructor // DOES NOT do a "deep" copy when copied/assigned (i.e., after copying both objects // will point to the same address) c
// some class that holds a raw pointer to memory on the heap
// DOES NOT delete it in its destructor
// DOES NOT do a "deep" copy when copied/assigned (i.e., after copying both objects
// will point to the same address)
class Point;
// function used to construct a point and allocate its data on the heap
Point AllocPoint();
// function used to release the memory of the point's data
void DeallocPoint(Point& p);
// Receives a pointer/c-array of Points, along with the number of points
// Doesn't own the memory
void Foo(Point* points, int npts);
在C++11中使用此API的最佳(最安全/最可读/最优雅)方式是什么。我不能简单地使用
vector
(其中PointDeleter
是我可以实现的一个简单的自定义deleter),因为这样我就不能使用函数Foo
(它需要Point*
而不是unique\u ptr*
)
谢谢“您”可以编写一个简单的包装来释放内存:
struct PointVectorWrapper {
vector<Point> points;
~PointVectorWrapper() {
for (Point& p : points) {
DeallocPoint(p);
}
}
PointVectorWrapper& operator=(const PointVectorWrapper&) = delete;
PointVectorWrapper(const PointVectorWrapper&) = delete;
};
// Now the usage is simple and safe:
PointVectorWrapper points;
// ... populate points ...
Foo(points.data(), points.size())
struct PointVectorWrapper{
矢量点;
~PointVectorWrapper(){
对于(点和点:点){
释放点(p);
}
}
PointVectorWrapper&运算符=(常量PointVectorWrapper&)=删除;
PointVectorWrapper(const PointVectorWrapper&)=删除;
};
//现在使用方法简单且安全:
点向量包装点;
// ... 填充点。。。
Foo(points.data(),points.size())
但这似乎有点“临时性”。什么是更标准的/可重用的解决方案? 如果你真的想让它看起来好看,你可能需要编写一套非常全面的包装器,它完全隐藏了库的API——有效地将整个库用一个以现代C++方式运行的包包起来,隐藏了所有的混乱。
这不是一项令人愉快的任务,但如果你能正确理解图书馆的行为,那么从长远来看,它应该会让你的生活更轻松。如果您不打算广泛使用此外部库,则可能不值得这样做。我将在RAII构建块中包装此非RAII C类API,然后在C++11代码中使用它们 例如:您可以定义一个
raipoint
类来包装(非RAII)Point
类,并在其构造函数调用的析构函数AllocPoint()
中定义析构函数DeallocPoint()
。然后,您可以定义适当的复制构造函数和复制操作符=
,或者只实现移动语义(使用移动构造函数和移动操作符=
),或者根据您的需求使包装类既可复制又可移动
然后,您可以简单地将std::vector
与基于RAII的包装器类一起使用
(这是一种通用的方法,当您想在现代C++代码中使用C库时,可以使用:您可以将“原始”C库句柄和对象封装在安全的RAII边界中,并使用您的现代C++代码中的这些健壮的安全包装类)< < /P> < P> >可以使用<代码> STD::vector < /C> >,调用<代码> FoO(& V(0), v、 size())。但是在这里管理内存可能很棘手, 因为
点
显然不提供任何干净的副本和
分配将调用分配器中的自定义删除程序
每个元素,即使它已被复制
如果向量实际上应该拥有这些点,那么可以进行换行
它位于一个更复杂的类中,该类为每个类调用AllocPoint
插入(并插入结果),以及每个
移除(以及向量上剩余的所有内容)
破坏)。此类不应允许对
点
(非常量运算符[]
、非常量迭代器等),
但是,由于这将允许更改中的任何指针
点
,并失去解除锁定点
工作所需的功能
正确地大概还有其他的操作功能
点
;你得把这些东西准备好
通过包装器接口。您可以使用带有自定义分配器的标准向量,该分配器在construct方法上调用AllocPoint,在destruct方法上调用DeallocPoint()
template<typename T>
class CustomAllocator : public std::allocator<T>
{
//Rebind and constructors
};
template<>
class CustomAllocator<Point> : public std::allocator<Point>
{
//Rebind and constructors
//For c++11
void construct( pointer p )
{
new (p) Point();
*p = AllocPoint();
}
void construct( pointer p, const_reference val )
{
construct(p);
//copy member from val to point if neccessary
};
void destroy( pointer p )
{
DeallocPoint(*p);
p->~Point();
}
};
typedef std::vector<Point, CustomAllocator<Point> > PointVector;
模板
类CustomAllocator:public std::allocator
{
//重新绑定和构造函数
};
模板
类CustomAllocator:public std::allocator
{
//重新绑定和构造函数
//对于c++11
void构造(指针p)
{
新(p)点();
*p=AllocPoint();
}
void构造(指针p,常量参考值)
{
构造(p);
//必要时将成员从val复制到点
};
无效销毁(指针p)
{
解除分配点(*p);
p->~点();
}
};
typedef std::vector PointVector;
看看。我想到的一件事是“扔掉库”。说真的。不幸的是,这不是我的选择……”“因为那样我就不能使用函数Foo
”-为什么不呢std::unique_ptr::get
将为您提供一个原始指针,同时保留所有权。是的,但要使用Foo,我需要一个点的C数组,那么如何传递向量中的所有点呢-(请编辑您的代码以消除危险性如果它充分说明了这一点,我们是否必须为每个问题提供完整和安全的解决方案?我们不能依靠OP将其充实到一个完整和安全的实现中吗?@BalogPal,正如Matthew Walton所说,我想用一点混乱作为pos来说明这一点不可能。不过我编辑了代码。我和弗雷德·布朗在一起,只有傻瓜才会把装有子弹的枪留在孩子手里。任何人都可以选择不发布答案,发布答案的人都应该保证它的质量。作为原件的替代品的包装必须同样有效,在复制后引入未定义的行为是错误的。@BalogPal我同意你的看法编辑后,这一点现在已经解决了,不是吗?问题是他不能将raipoint*
传递给他的函数。他必须用一个提取点并传递它的函数来包装每个相关函数。(他是否能实现正确的复制或移动语义也不清楚。)我还可以将unique_ptr与自定义的deleter一起使用,但在用法上存在一个问题:我将无法将points.data()传递给函数(因为它将返回raipoint*而不是Foo接受的Point*)@JamesKanze:RAII包装器类可以公开Get()
或GetPtr()
方法