我现在正在用c ++尝试STL,并发现了一个我不明白的问题。 我想象一个问题需要显示每个元素以及它在向量中出现的次数。由于我知道如何使用vector来完成这个问题,我尝试使用" set"或"地图"解决问题。
vector<char> v{ 'a', 'b', 'f', 'b', 'd', 'c', 'b', 'f', 's', 'v', 'x'};
map<char, int> m; // <key, counter>
for (char n : v)
m.insert(pair<char, int>(n, m[n]+1));
我认为每次发现密钥时它都会产生计数器加,但是,计数器没有工作,每个计数器都是0。 经过一些改变后:
vector<char> v{ 'a', 'b', 'f', 'b', 'd', 'c', 'b', 'f', 's', 'v', 'x'};
map<char, int> m; // <key, counter>
for (char n : v)
m.insert(pair<char, int>(n, m[n]++));
然后它工作。我不知道为什么。
答案 0 :(得分:2)
首先,您通过调用insert
更新地图条目的尝试都将被忽略,因为如果条目已存在,insert
不会执行任何操作。引用C++ reference:
如果容器尚未包含具有等效键的元素,则将元素插入容器中。
如果你稍微重写一下你的代码会更清楚一点:
for (char n : v)
{
int& count = m[n];
int new_count = count + 1;
pair<char, int> p(n, new_count);
m.insert(p); // ignored because the key already exists
}
第二个版本会直接修改地图内的计数,因为operator[]
会将引用返回到存储的值,而{{1直接操纵operator++
。您的第二个版本将重新显示如下:
int
即使您再次忽略尝试在地图中插入新对,但由于您直接修改了地图中存储的值,因此第二个版本会首先执行您希望代码执行的操作
答案 1 :(得分:1)
仔细查看insert函数:它只插入一个元素(如果尚未找到)!
相比之下,index operator会更新一个元素(如果找到),并创建一个具有默认值的新元素。所以:
m.insert(pair<char, int>(n, m[n]+1));
第一次调用它时,m[n]
已创建一个默认值为0的元素。然后,您在地图上调用insert
,但由于已找到该键,因此未插入任何对。所以你总是得到0 ......
m.insert(pair<char, int>(n, m[n]++));
实际上,从insert
看,没有区别:地图中的条目是在您第一次访问位置n
的地图时创建的,并且您可以直接递增条目。 insert
本身从不实际插入一对......
所以,如果你切断了&#34;什么都不做&#34;一段代码,剩下的就是:
for (char n : v)
m[n]++;
为了更好地理解,使用insert
的变体等同于上面的代码示例:
for (char n : v)
(m.insert(std::pair<char, int>(n, 0)).first->second)++;
有趣,不是吗?把它分成几块:
for (char n : v)
{
std::pair<std::map<char, int>::iterator, bool> result = m.insert(std::pair<char, int>(n, 0));
std::pair<char const, int>& entry = *result.first;
entry.second++;
}
这一行的核心部分是:
std::pair<std::map<char, int>::iterator, bool> result = m.insert(std::pair<char, int>(n, 0));
如果实际插入了元素,则该对的bool设置为true,否则设置为false。由于对特定情况下的这条信息不感兴趣,因此不再使用。
迭代器指向地图中的元素 - 新创建的元素(bool部分为true)或已找到的元素(bool部分为false)。