语言的哪一部分禁止更改std :: set的元素

Fra*_*eux 1 c++ std invariants stdset language-lawyer

An std::set是一种分类的关联容器,可快速查找其元素。密钥以一种有序的方式插入,一旦插入就不能修改密钥以保持该顺序。

考虑下面的示例,该示例构造一个std::setint*然后尝试破坏其元素的排序:

#include <iostream>
#include <set>

int values[] = { 50, 40, 30, 20, 10 };

// Comparator that sorts by pointed value
struct comparator {
    bool operator()(const int* left, const int* right) const {
        return *left < *right;
    }
};

using my_set_t = std::set<int*, comparator>;

// Checks if each of the elements of `values` are in the set
void output(const my_set_t & foo)
{
    for (auto & x : values) {
        std::cout << x << ' ' << foo.count(&x) << '\n';
    }
    std::cout << std::endl;
}

int main()
{
    // Insert the address of each element of `values` into the set
    my_set_t foo;
    for (auto & x : values) {
        foo.emplace(&x);
    }

    output(foo);
    // Changing `values[1]` to zero should break the sorting of the set
    values[1] = 0;
    output(foo);
}
Run Code Online (Sandbox Code Playgroud)

我得到的输出是:

50 1
40 1
30 1
20 1
10 1

50 1
0 0
30 0
20 0
10 0
Run Code Online (Sandbox Code Playgroud)

该表达式values[1] = 0;有效地set间接更改了的键之一。这破坏了顺序,因此似乎也破坏了count。我认为这也会破坏的大多数set其他功能。

代码显然有问题。据我所知,它遵循所有语言规则,并且似乎没有违反我可以为比较函数或找到的任何要求set。但是set尽管如此,提供的保证还是无法兑现的,这意味着我一定错过了一些东西。

Bri*_*ian 5

在C ++ 17中,有[associative.reqmts] / 3:

......对于任何两个密钥k1,并k2在同一容器中,调用comp(k1, k2)将总是返回相同的值。

因此,您的代码具有UB,因为它违反了此要求。