用于C ++ 11中RAW指针的SMART向量?

时间:2013-06-17 10:26:25

标签: 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)
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*)。

由于

5 个答案:

答案 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;
相关问题