【问题标题】:C++ Intersect two maps on keys, keep value of first mapC ++在键上将两个映射相交,保留第一个映射的值
【发布时间】:2014-07-18 08:00:13
【问题描述】:

我在使用 C++ 以及地图和交叉路口时遇到问题。

有 3 张地图,前两张是 map<int, double>,最后一张是 map<int, CustomType>。 我想从前 2 个映射中删除所有映射键实例,这些实例在第三个映射中不作为键存在。简而言之,我有第三张地图,其中包含对象列表,前两张地图包含有关对象的一些数据。在某个时间点,包含对象的地图被清理并删除了一些项目(用户交互),现在想要分别清理其他两个地图。

我尝试了以下方法:

map<int, double> map1, map2;
map<int, CustomType> map3;
for (auto it = map1.cbegin(); it != map1.cend(); )
{
    if ( map3.find(it->first) == map3.end() )
    {
        map2.erase(it);
        map1.erase(it++);
    }
    else ++it;
}

这在 map1.erase 行上给我一个错误“未分配指针被释放”。我研究了 set_intersection 但我不相信它在这种情况下会起作用,因为值会有所不同。

感谢任何帮助。

【问题讨论】:

    标签: c++ c++11 map intersection


    【解决方案1】:

    您需要独立地迭代map1map2。您不能使用 map1 的迭代器来操作另一个映射(从 map2erase 或使用 map2 执行任何其他操作)。
    所以代码应该是这样的:

    map<int, double> map1, map2;
    map<int, CustomType> map3;
    for (auto it = map1.cbegin(); it != map1.cend(); )
    {
        if ( map3.find(it->first) == map3.end() )
            it = map1.erase(it);
        else
            ++it;
    }
    
    for (auto it = map2.cbegin(); it != map2.cend(); )
    {
        if ( map3.find(it->first) == map3.end() )
            it = map2.erase(it);
        else
            ++it;
    }
    

    【讨论】:

    • 几乎...但是当您执行auto next = ++it; 时,您不小心跳过了map1/2 中的第一个元素,现在可能位于end() 元素上:如果是这样it-&gt;first in find 和在 erase 中使用 it 可能会崩溃和烧毁。
    • 为什么是 var next?完全没用和危险
    • @Velthune:在 C++03 中,有必要在使用擦除之前将迭代器存储到下一个元素,因为您擦除的迭代器随后失效并且无法递增。在 C++11 中更容易。
    • 您的答案有效(与下面其他人所说的相同)。问题是在 map2 上使用 map1 的迭代器。加倍代码工作正常。同意下一个不需要的变量。
    • @Velthune,好的,我已经重写了没有next。但是为什么你认为next 很危险?
    【解决方案2】:

    您正在尝试使用 map1 中的迭代器从 map2 中删除一个元素。那是行不通的。您需要从迭代器中获取键值并使用它从 map2 中擦除。当您为 map1 调用 erase 时,您的迭代器无效,因为您删除了它指向的元素。递增迭代器,然后使用键值调用map1.erase()。

    【讨论】:

    • “从迭代器中获取键值并使用它从 map2 中擦除”——即使这样还不够,因为任何仅在 map2 中的键都不会被擦除。
    【解决方案3】:

    您已经接近解决方案,但问题是迭代器实际上是一个指针。
    因此,您可以使用“it”同时删除 map1 和 map2。

    void removeUnexist(const map<int, double>& m, const map<int, CustomType>::iterator& it) {
       i = m.find(it->first);
       if(i == m.end()) {
          m.erase(i);
       }
    }
    
    map<int, double> map1, map2;
    map<int, CustomType> map3;
    
    for (auto it = map3.cbegin(); it != map3.cend(); it++) {
       removeUnexist(map1, it);
       removeUnexist(map2, it);
    }
    

    【讨论】:

    • 问题说“从前 2 个映射中删除所有映射键的实例,这些实例在第三个映射中不作为键存在”,但是您从第一个映射中删除了第三个映射的所有键2 张地图……完全不同。
    • 是的,正如你所说的“在 map1 和 map2 上调用了擦除”,这就是我的意思是“你正在从前 2 个映射中的第 3 个映射中删除任何键” - 但我应该有说“...key in the 3rd map...”以避免歧义,即使这样也可能会造成混淆。所以,让我从头开始解释:您想在 map1 和 map2 中找到不在 map3 中的键 - 通过迭代 map3 来做到这一点是不可能的,因为您只会看到 map3 中的键。
    猜你喜欢
    • 2012-07-17
    • 2020-05-13
    • 2012-06-03
    • 2016-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    • 2021-10-28
    相关资源
    最近更新 更多