【问题标题】:Structs in std::map<int,struct> memory leaking?std::map<int,struct> 内存泄漏中的结构?
【发布时间】:2021-10-08 20:42:47
【问题描述】:

我有以下结构和映射

struct dataStruct{
  unsigned long time;
  int32_t ch0;
  int32_t ch1;
  uint8_t state;
  int16_t temp;
  uint16_t vbat;
  int8_t rssi;
  };

std::map<uint32_t,struct dataStruct> uuidData = {};

还有一个循环等待新数据并用它填充地图。 (1)

for(;;)
{
    if (data_debug.is_new_data_available())
    {
        uint32_t uuid = data_debug.get_ID();
        uuidData[uuid] = {
            millis(), 
            data_debug.get_data1(), 
            data_debug.get_data2(), 
            data_debug.get_state(), 
            data_debug.get_temperature(),
            data_debug.get_battery_level(),
            data_debug.get_RSSI()
        };
    }
}

这可行,但是当我使用现有 UUID 获取数据时,我的直觉是旧结构永远不会被删除并且最终会泄漏。

我在下面有一个替代代码 (2) 试图绕过这个,但是当 UUID 被复制时,结构被垃圾填充。 (1) 中的代码是否泄漏或 c++ 在不再需要该结构时自动释放空间? (我知道这听起来像是垃圾回收,但我不知道 c++ 如何处理结构)

(2)

    if(uuidData.count(uuid)){
        uuidData[uuid].time = millis();
        uuidData[uuid].ch0 = data_debug.get_data1();
        uuidData[uuid].ch1 = data_debug.get_data2();
        uuidData[uuid].state = data_debug.get_state();
        uuidData[uuid].temp = data_debug.get_temperature();
        uuidData[uuid].vbat = data_debug.get_battery_level();
        uuidData[uuid].time = data_debug.get_RSSI();
    }
    else{
        uuidData[uuid] = {
            millis(), 
            data_debug.get_data1(), 
            data_debug.get_data2(), 
            data_debug.get_state(), 
            data_debug.get_temperature(),
            data_debug.get_battery_level(),
            data_debug.get_RSSI()
            };
}

【问题讨论】:

  • 如果uuid 存在,它会被重用。 uuidData[uuid] = { ... };{ ... } 创建的临时对象复制到map 中的现有对象中。当uuid 被删除或地图超出范围时,map 将处理对象的正确销毁和释放。
  • 为什么你的直觉是旧结构永远不会被删除?
  • @NathanPierson 因为我从来没有明确地调用过删除。
  • 只有deletenew。如果您的代码没有new,则不需要delete
  • 次要注意:由于您使用的是 C++ 而不是 C,因此无需编写 std::map&lt;uint32_t,struct dataStruct&gt;。您可以将其简化为std::map&lt;uint32_t, dataStruct&gt;

标签: c++ std esp32 stdmap


【解决方案1】:

让我们分解示例 1 发生的情况(完成此任务的正确方法)

uuidData[uuid] = {
            millis(), 
            data_debug.get_data1(), 
            data_debug.get_data2(), 
            data_debug.get_state(), 
            data_debug.get_temperature(),
            data_debug.get_battery_level(),
            data_debug.get_RSSI()
        };

        {
            millis(), 
            data_debug.get_data1(), 
            data_debug.get_data2(), 
            data_debug.get_state(), 
            data_debug.get_temperature(),
            data_debug.get_battery_level(),
            data_debug.get_RSSI()
        };

创建并初始化一个临时的dataStruct 变量,这是一个仅在不再需要时才会存在的自动变量。当表达式结束时,临时对象超出范围并被销毁。

uuidData[uuid]

uuidData 中查找与uuid 匹配的键。如果找不到,它会创建一个空的dataStruct 并将其映射到密钥。这个新的dataStructuuidData 管理。它从哪里来,到哪里去,不是你关心的。一旦映射到uuiddataStruct 存在,就会返回对它的引用。

现在我们在地图中引用了现有的dataStruct 和临时的dataStruct= 只是将右侧的临时内容复制到左侧引用所代表的对象中。左侧对象中的任何内容都将被覆盖,但该对象仍然存在并且仍由uuidData 管理。当它从uuidData 中删除或uuidData 超出范围时,它将被正确销毁和释放。表达式完成后,临时会自动为您销毁 (ergo the name Automatic variable)。

这里没有泄漏的可能性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    • 2010-11-25
    • 2016-03-28
    • 2011-10-04
    • 2013-03-08
    相关资源
    最近更新 更多