【问题标题】:Weird behaviour with unordered_map of vectors and erase-remove idiom in C++14C++14 中向量的 unordered_map 和擦除删除习语的奇怪行为
【发布时间】:2019-03-17 08:43:21
【问题描述】:

所以我在undirected graph 中计算Biconnected Components (BCC),计算后我的算法在一些密件抄送中也包含一些Bridge 边,因此作为后处理步骤,我在每个BCC 上运行一个循环(表示为vector<pair<int, int>>,每个pair<int, int> 表示该密件抄送中的edge。)我是这样做的:

auto pred = [&Bridges](pair<int, int>& edge) -> bool
{
    return Bridges.find(edge) != Bridges.end();
};

for (auto bcc = BCC.begin(); bcc != BCC.end(); bcc++)
{
    vector<pair<int, int>>& BCCList = (bcc->second);
    BCCList.erase(remove_if(
        BCCList.begin(), BCCList.end(), pred), BCCList.end());
}

Bridges 又是pair&lt;int, int&gt;s 的set,包含我的算法找到的所有桥边。

BCCunordered_map&lt;int, vector&lt;pair&lt;int, int&gt;&gt;&gt;

上面的代码按预期工作,删除了之前可能存在于 BCC 向量中的任何 Bridge 边缘。但是,如果我稍作改动并这样做:

auto pred = [&Bridges](pair<int, int>& edge) -> bool
{
    return Bridges.find(edge) != Bridges.end();
};

for (auto bcc = BCC.begin(); bcc != BCC.end(); bcc++)
{
    vector<pair<int, int>> BCCList = (bcc->second);
    BCCList.erase(remove_if(
        BCCList.begin(), BCCList.end(), pred), BCCList.end());
}

我所做的只是在for-loop 的第一行中删除BCCList 之前的&amp;。这使得代码无法工作,并产生一个结果,好像这个 for-loop 从未执行过;任何 BCC 中的桥边都不会被删除,因此最终会计算错误的 BCC。请告诉我为什么会这样?

我一直认为,如果我在unordered_map 上有一个类似bcc 的迭代器,那么bcc-&gt;first 就是key(这里,bcc-&gt;first 应该是一个int)而bcc-&gt;secondvalue(这里,bcc-&gt;second 应该是 vector&lt;pair&lt;int, int&gt;&gt;)。这不正确吗?为什么我必须明确指定 &amp;(引用变量)才能使代码正常工作?

这种行为可能与remove_if 有关吗?

【问题讨论】:

标签: c++ dictionary vector c++14


【解决方案1】:
vector<pair<int, int>>& BCCList = (bcc->second);

这里,BCCList 是存储在bcc-&gt;second 中的向量的引用(替代名称)。无论您对BCCList 所做的任何更改实际上都是对bcc-&gt;second 所做的。

vector<pair<int, int>> BCCList = (bcc->second);

这里,BCCList 是存储在bcc-&gt;second 中的向量的副本。这是一个单独的对象。对其进行的更改根本不会影响bcc-&gt;second

这是一个更简单的例子,它应该更明显地发生了什么:

int data = 42;
int *bcc = &data;

int &ref = *bcc;
ref = 314;

int cop = *bcc;
cop = -42;

我认为您不会期望分配 cop = -42; 会修改 data。在您的代码中,情况完全相同。

【讨论】:

    【解决方案2】:

    在您的原始代码中,BCCList 是对密件抄送中元素的引用。您在BCCList 上所做的一切,实际上都是针对原始元素进行的。

    当您删除 &amp; 时,BCCList 是一个独立值,它使用原始副本进行初始化。您对它所做的一切都保持在该值的本地,并在下一次迭代(或离开循环时)丢失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-09
      相关资源
      最近更新 更多