Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+中原始指针的智能向量+;11?_C++_C++11_Smart Pointers - Fatal编程技术网

C++ C+中原始指针的智能向量+;11?

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

我使用的是一个旧的开源库,其中包含以下(简化的)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
(其中
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()
方法