C++:有条件地将一个键和值插入到std :: map中

jes*_*per 10 c++

如果我做:

std::map<string, size_t> word_count;
size_t value = word_count.count("a") == 0 ? 1 : 2;
word_count["a"] = value;
Run Code Online (Sandbox Code Playgroud)

那么word_count ["a"]的最终值是1,正如我所料.如果相反,我做:

std::map<string, size_t> word_count;
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
Run Code Online (Sandbox Code Playgroud)

那么word_count ["a"]的最终值是2.为什么!?

chr*_*ris 10

正式地,可以首先评估任务的任何一方.由实现来决定哪个.如果word_count不包含"a",则插入一个,并返回对它的左值引用.如果word_count确实包含一个,则只发生后一个部分.尽管首先评估哪一方的不确定性,您可以遵循可能的执行:

左边第一

没有元素存在:

operator[]插入元素,因为它不存在.count()找到它并返回1,因此最终为它赋值为2.

元素存在:

operator[]返回现有元素并count()找到它并返回1,因此最终为它赋值为2.

右边第一

没有元素存在:

count()返回0,所以你从右边得到1.然后,"a"插入到地图中并赋值为1.

元素存在:

count()返回1,所以从右侧得到2.然后,word_count["a"]访问并分配2.

结论

简而言之,你不能依靠它来做你想做的事情,所以最好使用你可以依赖的东西.mrfontanini提出了一个很好的建议,所以我会稍微编辑一下:

word_count["a"]++;
word_count["a"] = std::min(word_count["a"], 2);
Run Code Online (Sandbox Code Playgroud)

第一行确保它被插入并且值至少为1.在重复执行此操作的情况下,第二行将该值限制为最大值2.

笔记

我的答案基于两件事:

  1. 当选择要评估的一侧时,必须在另一侧开始之前评估整个侧面.

  2. 构造如word_count["a"] = 1展示明确定义的行为,即使在插入元素然后分配元素的情况下也是如此.

下面有一些关于这些是否属实的辩论和讨论.我现在变得更加正式了.

  • 不需要先评估它.我相信这是一个未定义行为的情况([读取值并在没有序列点的情况下修改它](尽管http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points))我从来没有像这样间接地调用它. (4认同)
  • 它真的没有什么不同(只是表面上看):`(x = 0)=(x == 0)?1:2;` (3认同)

Bil*_*nch 5

看着这一行:

word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
Run Code Online (Sandbox Code Playgroud)

相信如果word_count["a"]在执行该行之前地图中不存在,则会导致未定义的行为。

这是因为word_count["a"]如果一个条目不存在,将在地图中创建一个条目,这将改变word_count.count("a"). 我们也不需要在这两个调用之间进行排序。