如何正确分配和解除分配向量图

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);

您无需执行任何其他操作。这也将破坏并释放向量。

当您不再需要地图及其包含的矢量时,您也无需执行任何操作。当定义地图的范围离开时,地图的析构函数将自动清理所有内容。