从 std::vector 接管内存
taking over memory from std::vector
我使用一个外部库来处理大量数据。数据由原始指针加上长度传入。该库不声明指针的所有权,但在处理完数据时调用提供的回调函数(具有相同的两个参数)。
通过使用std::vector<T>
可以方便地准备数据,我宁愿不放弃这种便利。复制数据完全是不可能的。因此,我需要一种方法来"接管"std::vector<T>
拥有的内存缓冲区,并(稍后)在回调中释放它。
我当前的解决方案如下所示:
std::vector<T> input = prepare_input();
T * data = input.data();
size_t size = input.size();
// move the vector to "raw" storage, to prevent deallocation
alignas(std::vector<T>) char temp[sizeof(std::vector<T>)];
new (temp) std::vector<T>(std::move(input));
// invoke the library
lib::startProcesing(data, size);
并且,在回调函数中:
void callback(T * data, size_t size) {
std::allocator<T>().deallocate(data, size);
}
此解决方案有效,因为标准分配器的 deallocate
函数忽略其第二个参数(元素计数)并简单地调用 ::operator delete(data)
。否则,可能会发生不好的事情,因为输入向量的size
可能比其capacity
小很多。
我的问题是:是否有一种可靠的(C++标准)方法来接管std::vector
的缓冲区并在以后的某个时间"手动"释放它?
你不能从向量中获取内存的所有权,但你可以用另一种方式解决你的潜在问题。
以下是我处理它的方法 - 由于静态全局变量而不是线程安全,它有点笨拙,但它可以通过一些简单的锁定来访问registry
对象来实现。
static std::map<T*, std::vector<T>*> registry;
void my_startProcessing(std::vector<T> * data) {
registry.put(data->data(), data);
lib::startProcesing(data->data(), data->size());
}
void my_callback(T * data, size_t length) {
std::vector<T> * original = registry.get(data);
delete original;
registry.remove(data);
}
现在你可以做
std::vector<T> * input = ...
my_startProcessing(input);
但要小心!如果在调用my_startProcessing
后向输入添加/删除元素,则会发生不好的事情 - 库的缓冲区可能会失效。(您可能被允许更改向量中的值,因为我相信这将正确写入 to 数据,但这也取决于库允许的内容。
如果 T
= bool
,这也不起作用,因为std::vector<bool>::data()
不起作用。
您可以在向量上创建自定义类构建。
这里的关键点是在构造函数中使用移动语义SomeData
。
- 您无需复制即可获得准备好的数据(请注意,源向量将被清除)
- 数据将由
thisData
矢量析构函数正确处理 - 源载体可以毫无问题地处理
由于底层数据类型将是数组,因此您可以计算开始指针和数据大小(请参阅下面的SomeDataImpl.h
):
一些数据.h
#pragma once
#include <vector>
template<typename T>
class SomeData
{
std::vector<T> thisData;
public:
SomeData(std::vector<T> && other);
const T* Start() const;
size_t Size() const;
};
#include "SomeDataImpl.h"
SomeDataImpl.h
#pragma once
template<typename T>
SomeData<T>::SomeData(std::vector<T> && otherData) : thisData(std::move(otherData)) { }
template<typename T>
const T* SomeData<T>::Start() const {
return thisData.data();
}
template<typename T>
size_t SomeData<T>::Size() const {
return sizeof(T) * thisData.size();
}
使用示例:
#include <iostream>
#include "SomeData.h"
template<typename T>
void Print(const T * start, size_t size) {
size_t toPrint = size / sizeof(T);
size_t printed = 0;
while(printed < toPrint) {
std::cout << *(start + printed) << ", " << start + printed << std::endl;
++printed;
}
}
int main () {
std::vector<int> ints;
ints.push_back(1);
ints.push_back(2);
ints.push_back(3);
SomeData<int> someData(std::move(ints));
Print<int>(someData.Start(), someData.Size());
return 0;
}
以任何可移植的方式做到这一点,但你可以以一种可能适用于大多数C++实现的方式做到这一点。 在VS 2017上进行快速测试后,此代码似乎可以工作。
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
T* HACK_stealVectorMemory(vector<T>&& toStealFrom)
{
// Get a pointer to the vector's memory allocation
T* vectorMemory = &toStealFrom[0];
// Construct an empty vector in some stack memory using placement new
unsigned char buffer[sizeof(vector<T>)];
vector<T>* fakeVector = new (&buffer) vector<T>();
// Move the memory pointer from toCopy into our fakeVector, which will never be destroyed.
(*fakeVector) = std::move(toStealFrom);
return vectorMemory;
}
int main()
{
vector<int> someInts = { 1, 2, 3, 4 };
cout << someInts.size() << endl;
int* intsPtr = HACK_stealVectorMemory(std::move(someInts));
cout << someInts.size() << endl;
cout << intsPtr[0] << ", " << intsPtr[3] << endl;
delete intsPtr;
}
输出:
4
0
1, 4
- 当vector是tje全局变量时,c++中vector的内存管理
- 为什么 vector 的随机访问迭代器给出与指针不同的内存地址?
- 使 std::vector 分配对齐内存的现代方法
- 如何为 std::vector 分配内存,然后稍后为某些元素调用构造函数?
- 将 vector<vector<int>> 传递到函数中会产生内存错误
- <char> 使用 Vulkan 映射内存时如何使用 std::vector 而不是 void**?
- C++ 中 std::vector 的内存问题
- vector是否为std::移动的对象连续分配内存
- 释放 std::vector 中指针内存的最有效方法是什么?
- 如何让 'std::vector' <int32_t>从 'std::vector&&' 中获取内存<uint32_t>?
- 访问"std::vector"的保留但未调整大小的内存作为原始内存是否安全?
- 如何使用 std::vector 防止内存重新分配
- 让 'std::vector<unsigned char>' 从 'std::string' 中窃取内存
- 将 std::vector<int> 从原始内存转换为数组
- 给出一个 std::vector 对另一个向量的内存的所有权?
- std::vector<std::vector<int>>:调试断言失败。C++矢量下标超出范围保留内存
- 内存覆盖在我自己的 Vector 类中
- 释放 std::vector 中的内存
- 删除[]是否可以与通用数组正常使用?如果是这样,为什么使用std :: vector ::擦除它会导致释放内存的错误
- 为什么libstdc++的std::vector的ctor实现不会导致内存泄漏?