You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无内存泄漏地深拷贝含Boost侵入式列表的Map?

解决Boost侵入式列表Map深拷贝的内存泄漏问题

核心问题分析

Boost侵入式容器(如list)的设计原则是不管理元素内存,容器仅维护元素间的链接关系,因此深拷贝时手动创建的Str对象需要我们自行负责销毁,否则会导致内存泄漏。你尝试通过继承list添加析构清理逻辑的思路是可行的,编译错误源于unordered_map::insert的初始化列表推导问题,可通过调整插入方式解决。

方案1:继承侵入式列表实现自动清理(推荐,若读取线程可兼容新类型)

此方案让拷贝后的列表在销毁时自动清理元素,无需手动调用清理函数:

  1. 定义带自动清理逻辑的列表子类:
#include <boost/intrusive/list.hpp>
#include <unordered_map>

using namespace boost::intrusive;

struct Tag;
using Hook = list_base_hook< tag<Tag> >;

class Str : public Hook
{
public:
    Str(int n) : n_(n) {}
    Str(const Str& s) : n_(s.n_) {}

    int n_;
};

// 原列表类型,供写入线程使用
using List = list< Str, cache_last<true>, base_hook<Hook> >;
using Map = std::unordered_map<std::string, List>;

// 带自动清理的列表子类,供拷贝后的读取线程使用
class List_ : public List
{
public:
    // 显式默认移动构造/赋值,确保容器移动操作正常
    List_(List_&&) = default;
    List_& operator=(List_&&) = default;

    ~List_()
    {
        while (!empty())
        {
            Str* node = &front();
            pop_front();
            delete node;
        }
    }
};

// 拷贝专用的Map类型
using CopyMap = std::unordered_map<std::string, List_>;
  1. 修改深拷贝函数,使用emplace避免初始化列表编译错误:
void deep_copy_map(const Map& orig, CopyMap& copy)
{
    for (const auto& entry : orig) {
        List_ list_copy;
        for (const auto& str : entry.second) {
            // 拷贝构造新的Str对象并加入列表
            list_copy.push_back(*new Str(str));
        }
        // 使用emplace直接构造键值对,绕过初始化列表的推导问题
        copy.emplace(entry.first, std::move(list_copy));
    }
}

当CopyMap对象被销毁时,每个List_的析构函数会自动遍历销毁所有Str元素,彻底避免内存泄漏。

方案2:不修改容器类型,手动清理拷贝元素(兼容原读取线程逻辑)

若读取线程无法修改类型,必须使用原Map类型,可在读取线程使用完拷贝的Map后手动清理元素:

  1. 深拷贝函数保持原逻辑,调整插入方式避免编译问题:
void deep_copy_map(const Map& orig, Map& copy)
{
    for (const auto& entry : orig) {
        List list_copy;
        for (const auto& str : entry.second) {
            list_copy.push_back(*new Str(str));
        }
        // 使用std::make_pair构造可移动的键值对
        copy.insert(std::make_pair(entry.first, std::move(list_copy)));
    }
}
  1. 提供清理函数,读取线程使用完拷贝的Map后调用:
void cleanup_map(Map& map)
{
    for (auto& entry : map) {
        auto& list = entry.second;
        while (!list.empty()) {
            Str* node = &list.front();
            list.pop_front();
            delete node;
        }
    }
}

如果读取线程无法直接调用清理函数,可封装成RAII类自动触发清理:

class MapWrapper {
public:
    Map map;

    ~MapWrapper() {
        cleanup_map(map);
    }
};

深拷贝时直接构造MapWrapper对象,读取线程使用wrapper.map即可,MapWrapper销毁时会自动清理所有Str元素。

内容的提问来源于stack exchange,提问作者CforLinux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 11:25:09