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
并变成非拥有的类中.
这是一个可怕的黑客应该允许你做你需要的,但它依赖于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)