如何正确分配和解除分配向量图
How to properly allocate and deallocate a map of vectors
我试图将数据保存在一个无序的矢量映射中,使用 uint32_t 个地址作为键。向量需要存储在堆中,所以
即使函数超出范围,我仍然可以访问数据。我是这样分配的:
using vectorBuffer = std::vector<uint8_t>;
using I2cVectorMap = std::unordered_map<address_t, vectorBuffer>;
using I2cVectorEntry = std::pair<address_t, vectorBuffer>;
if(auto i2cIter = i2cVectorMap.find(address); i2cIter == i2cVectorMap.end()) {
vectorBuffer * receiveVector = new vectorBuffer(maxReplyLen);
i2cVectorMap.insert(I2cVectorEntry(address, *receiveVector));
}
else {
// Already in map. readjust size
vectorBuffer * existingVector = &i2cIter->second;
existingVector->resize(maxReplyLen);
existingVector->shrink_to_fit();
}
像这样的重新分配(根据各种来源的建议,用空向量交换向量):
// getting the address from another object.
address_t deviceAddress = i2cCookie->getAddress();
if(auto i2cIter = i2cVectorMap.find(deviceAddress); i2cIter != i2cVectorMap.end()) {
vectorBuffer().swap(i2cIter->second);
}
这是正确的实施方式吗?我会将映射条目的地址传递给启动 I2C 传输的驱动程序函数或传递给处理数据的另一个对象。我想确保我没有内存泄漏。
提前致谢!
不,您不应该使用 new
。首先需要直接 new
的情况很少见。
您无需手动创建任何具有动态存储持续时间 ("on the heap") 的对象。标准库容器直接存储对象,而不是对象的引用或指针。他们会为这些对象进行分配,自己构造。您只需向容器 (copy/move) 构造存储元素的容器成员函数提供构造函数参数。
您可以将对象声明为自动变量(即 "on the stack"):
vectorBuffer receiveVector(maxReplyLen);
i2cVectorMap.insert(I2cVectorEntry(address, receiveVector));
或者对中间向量实例使用临时变量而不是命名变量(这也将使用移动而不是复制操作,因此性能更好):
i2cVectorMap.insert(I2cVectorEntry(address, vectorBuffer(maxReplyLen)));
并且如果您使用 emplace
而不是 insert
,您也可以删除冗余对类型:
i2cVectorMap.emplace(address, vectorBuffer(maxReplyLen));
您不需要指针来调用映射中对象的方法:
vectorBuffer& existingVector = i2cIter->second;
existingVector.resize(maxReplyLen);
existingVector.shrink_to_fit();
要从地图中删除一个元素,您可以使用其 .erase
成员函数:
i2cVectorMap.erase(deviceAddress);
您无需执行任何其他操作。这也将破坏并释放向量。
当您不再需要地图及其包含的矢量时,您也无需执行任何操作。当定义地图的范围离开时,地图的析构函数将自动清理所有内容。
我试图将数据保存在一个无序的矢量映射中,使用 uint32_t 个地址作为键。向量需要存储在堆中,所以 即使函数超出范围,我仍然可以访问数据。我是这样分配的:
using vectorBuffer = std::vector<uint8_t>;
using I2cVectorMap = std::unordered_map<address_t, vectorBuffer>;
using I2cVectorEntry = std::pair<address_t, vectorBuffer>;
if(auto i2cIter = i2cVectorMap.find(address); i2cIter == i2cVectorMap.end()) {
vectorBuffer * receiveVector = new vectorBuffer(maxReplyLen);
i2cVectorMap.insert(I2cVectorEntry(address, *receiveVector));
}
else {
// Already in map. readjust size
vectorBuffer * existingVector = &i2cIter->second;
existingVector->resize(maxReplyLen);
existingVector->shrink_to_fit();
}
像这样的重新分配(根据各种来源的建议,用空向量交换向量):
// getting the address from another object.
address_t deviceAddress = i2cCookie->getAddress();
if(auto i2cIter = i2cVectorMap.find(deviceAddress); i2cIter != i2cVectorMap.end()) {
vectorBuffer().swap(i2cIter->second);
}
这是正确的实施方式吗?我会将映射条目的地址传递给启动 I2C 传输的驱动程序函数或传递给处理数据的另一个对象。我想确保我没有内存泄漏。
提前致谢!
不,您不应该使用 new
。首先需要直接 new
的情况很少见。
您无需手动创建任何具有动态存储持续时间 ("on the heap") 的对象。标准库容器直接存储对象,而不是对象的引用或指针。他们会为这些对象进行分配,自己构造。您只需向容器 (copy/move) 构造存储元素的容器成员函数提供构造函数参数。
您可以将对象声明为自动变量(即 "on the stack"):
vectorBuffer receiveVector(maxReplyLen);
i2cVectorMap.insert(I2cVectorEntry(address, receiveVector));
或者对中间向量实例使用临时变量而不是命名变量(这也将使用移动而不是复制操作,因此性能更好):
i2cVectorMap.insert(I2cVectorEntry(address, vectorBuffer(maxReplyLen)));
并且如果您使用 emplace
而不是 insert
,您也可以删除冗余对类型:
i2cVectorMap.emplace(address, vectorBuffer(maxReplyLen));
您不需要指针来调用映射中对象的方法:
vectorBuffer& existingVector = i2cIter->second;
existingVector.resize(maxReplyLen);
existingVector.shrink_to_fit();
要从地图中删除一个元素,您可以使用其 .erase
成员函数:
i2cVectorMap.erase(deviceAddress);
您无需执行任何其他操作。这也将破坏并释放向量。
当您不再需要地图及其包含的矢量时,您也无需执行任何操作。当定义地图的范围离开时,地图的析构函数将自动清理所有内容。