在不释放内存的情况下销毁std :: vector

Jan*_*egg 10 c++ vector std stdvector c++11

假设我有一个函数将数据导入std向量:

void getData(std::vector<int> &toBeFilled) {
  // Push data into "toBeFilled"
}
Run Code Online (Sandbox Code Playgroud)

现在我想将这些数据发送到另一个函数,该函数应在完成时释放数据:

void useData(int* data)
{
  // Do something with the data...
  delete[] data;
}
Run Code Online (Sandbox Code Playgroud)

这两个函数(getData和useData)都是固定的,无法更改.复制数据一次时这很好用:

{
  std::vector<int> data;
  getData(data);
  int *heapData = new int[data.size()];
  memcpy(heapData, data.data(), data.size()*sizeof(int));
  useData(heapData);
  data.clear();
}
Run Code Online (Sandbox Code Playgroud)

但是,这个memcpy操作很昂贵而且并不是真正需要的,因为数据已经在堆上了.是否可以直接提取和使用std向量分配的数据?像(伪代码)的东西:

{
  std::vector<int> data;
  getData(data);
  useData(data.data());
  data.clearNoDelete();
}
Run Code Online (Sandbox Code Playgroud)

编辑:

这个例子可能没有多大意义,因为在函数调用useData之后可以释放向量.但是,在实际代码中,useData不是一个函数,而是一个接收数据的类,这个类的寿命比向量长...

Lig*_*ica 25

没有.

您正在使用的API有一个合同,声明它接受您提供的数据的所有权,并且该数据是通过指针提供的.这基本上排除了使用标准向量.

Vector将始终确保释放它分配的内存并安全地销毁它包含的元素.这是其保证合同的一部分,你不能拒绝.

必须使数据的副本,如果你想利用这些所有权......或移动每个元素到你自己的容器.或者首先从你自己开始new[](唉)虽然你至少可以将这一切包含在一些模仿std::vector并变成非拥有的类中.

  • @TonyD:这就是UB.我认为这是一个错误的解决方案 (4认同)
  • *"Vector总能确保释放它分配的内存,并安全地销毁它所包含的元素.......你不能把它关掉."* - 你可以将`new`放在原来的'vector'上的空`vector <int>` `这样析构函数 - 运行时 - 不知道早期的分配; 这里真正的问题是默认分配器不使用`new []`,即使它确实`.data()`可能不会产生相同的值,所以`.data()`值上的`delete []`是不安全的,写一个自定义分配器来解决所有涉及不可避免的低效率的问题+一个`reinterpret_cast`来调用`getData()`. (2认同)

Rei*_*ica 7

这是一个可怕的黑客应该允许你做你需要的,但它依赖于Undefined Behavior做最简单的事情.我们的想法是创建自己的分配器,它与布局兼容std::allocator并对向量进行输入:

template <class T>
struct CheatingAllocator : std::allocator<T>
{
  using typename std::allocator<T>::pointer;
  using typename std::allocator<T>::size_type;

  void deallocate(pointer p, size_type n) { /* no-op */ }

  // Do not add ANY data members!!
};


{
  std::vector<int, CheatingAllocator<int>> data;
  getData(reinterpret_cast<std::vector<int>&>(data)); // type pun, `getData()` will use std::allocator internally
  useData(data.data());
  // data actually uses your own allocator, so it will not deallocate anything
}
Run Code Online (Sandbox Code Playgroud)

请注意,它像黑客一样黑客和不安全.它依赖于不改变的内存布局,它依赖于在其功能内部std::allocator使用.我不会在生产代码中使用它,但我相信它是一个(绝望的)解决方案.new[]allocate


@TonyD在评论中正确地指出了std::allocator很可能不会在new[]内部使用.因此,上面很可能在delete[]内部失败useData().同样的@TonyD也提出了一个关于使用reserve()(希望)防止内部重新分配的好处getData().所以更新后的代码如下所示:

template <class T>
struct CheatingAllocator : std::allocator<T>
{
  using typename std::allocator<T>::pointer;
  using typename std::allocator<T>::size_type;

  pointer allocate(size_type n) { return new T[n]; }

  void deallocate(pointer p, size_type n) { /* no-op */ }

  // Do not add ANY data members!!
};


{
  std::vector<int, CheatingAllocator<int>> data;
  data.reserve(value_such_that_getData_will_not_need_to_reallocate);
  getData(reinterpret_cast<std::vector<int>&>(data)); // type pun, `getData()` will use std::allocator internally
  useData(data.data());
  // data actually uses your own allocator, so it will not deallocate anything
}
Run Code Online (Sandbox Code Playgroud)