我试图将数据保存在无序的向量映射中,使用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
的情况很少见。
您不需要手动创建任何具有动态存储持续时间("在堆上"(的对象。标准库容器直接存储对象,而不是对象的引用或指针。他们将为这些对象进行分配并自行构建。您只向容器成员函数提供构造函数参数,容器(复制/移动(从这些函数构造存储的元素。
您可以将对象声明为自动变量(即"在堆栈上"(:
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);
你不需要做任何其他事情。这将破坏并释放向量。
当你不再需要映射及其包含的向量时,你也不需要做任何事情。当定义映射的范围剩下时,映射的析构函数将自动清理所有内容。