插入自己的尺寸 std::map

Inserting its own size to std::map

我刚刚在我的代码 (C++14) 中遇到了一个奇怪的错误,这是由 std::map 的意外(至少对我而言)行为引起的。这是一个演示行为的简单示例:

#include <iostream>
#include <map>

int main()
{
    std::map<int, int> m;
    for(int i = 0; i < 3; ++i) {
        m[m.size()] = m.size();
    }
    for(const std::pair<int, int>& e : m) {
        std::cout << e.first << " " << e.second << std::endl;
    }
    
    return 0;
}

这会打印:

0 1                                                                                                                                                                            
1 2                                                                                                                                                                            
2 3

我期待:

0 0
1 1
2 2

这是怎么回事?地图首先添加一个设置了 first 的新元素,然后才(当地图的大小已经增加时)设置 second?我不太明白为什么这是有道理的。还是有其他解释?谢谢!

让我们更详细地写下循环代码:

for(int i = 0; i < 3; ++i) {
    int& temp = m.operator[](m.size());
    temp = m.size();
}

请注意,调用 operator[] 已经在为它赋值之前插入默认的已初始化元素。因此,在评估分配的右侧时,地图已经增长。

要解决此问题,请确保在使用之前确定大小 operator[]:

for(int i = 0; i < 3; ++i) {
    size_t v = m.size();
    m[v] = v;
}

表达式中发生了一些事情

m[m.size()] = m.size();

首先,需要对m[m.size()]= m.size()进行评估。在 C++14 中,求值顺序是不确定的。 m[m.size()] 可能先发生,也可能后发生。如果它先发生,那么您会看到收到的结果。如果第二次发生,那么您将获得预期的输出。

如果你愿意

0 0
1 1
2 2

那你要自己保证下单。您可以使用 map::insert() 来做到这一点:

m.insert(m.size(), m.size());

从 C++17 开始,情况不再如此。 The standard 改为:

The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand; their result is an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.

它现在保证 = m.size() 发生在 m[m.size()] 之前,并且您得到您期望的顺序。