我正在使用一个旧的开源库,其中包含以下(简化的)感兴趣的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)
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<unique_ptr<Point, PointDeleter>>
(其中PointDeleter
是一个我可以实现的简单自定义删除器),因为那时我将无法使用函数Foo
(期望{{1}而不是Point*
)。
由于
答案 0 :(得分:4)
如果你真的想让它看起来不错,那么你可能需要编写一组非常全面的包装器来完全隐藏库的API - 有效地将整个库包装成一个以现代C ++方式运行的库在外面并隐藏所有内部的混乱。
这不是一项令人愉快的任务,但是如果你能够获得该库的行为,那么它应该会让你的生活更加轻松。如果你不打算非常广泛地使用这个外部库,那么可能不值得。
答案 1 :(得分:4)
我会在 RAII 构建块中包装这个非RAII C类API,然后在C ++ 11代码中使用它们。
例如:您可以在析构函数RaiiPoint
中定义包含(非RAII)Point
类的AllocPoint()
类,并在其构造函数调用DeallocPoint()
中定义。然后,您可以定义正确的复制构造函数并复制operator=
,或者只是实现移动语义(使用移动构造函数并移动operator=
),或者根据您的要求使包装类既可复制又可移动。
然后,您可以简单地将std::vector<RaiiPoint>
与基于RAII的包装类一起使用。
(这是一种通用方法,当您想在现代C ++代码中使用C库时可以使用它:您可以将“原始”C库句柄和对象包装在安全的RAII边界中,并且在现代C ++代码中使用这些健壮的安全包装类。)
答案 2 :(得分:4)
您可以使用std::vector<Point>
,呼叫Foo( &v[0],
v.size() )
。但是在这里管理内存可能很棘手,
因为Point
显然不提供任何干净的副本
分配;将调用分配器中的自定义删除器
每个元素,即使它被复制。
如果矢量实际上应该拥有这些点,那么你可以换行
它在一个更复杂的类中,每个类都调用AllocPoint
插入(并插入结果),并为每个插入DeallocPoint
删除(以及矢量中剩余的所有内容
破坏)。这个类不允许写入访问权限
Point
(非const operator[]
,非const迭代器等),
但是,因为这将允许更改任何指针
Point
,并且失去了DeallocPoint
工作所需的内容
正确。据推测,还有其他操作功能
Point
;你必须安排这些是可用的
通过包装器界面。
答案 3 :(得分:1)
“你”可以编写一个简单的包装来释放内存:
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())
但这似乎有点“特别”。什么是更标准/可重复使用的解决方案?
答案 4 :(得分:1)
您可以使用带有自定义分配器的标准向量,在构造方法上调用AllocPoint,在析构方法上调用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;