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

标签 c++ language-lawyer std stdset invariants

std::set 是一个排序的关联容器,可以快速查找其元素。键以排序的方式插入,并且一旦插入就不能修改键以保留该顺序。

考虑以下构建 int*std::set 的演示,然后尝试打破它的元素排序:

#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);
}

我得到的输出是:

50 1
40 1
30 1
20 1
10 1

50 1
0 0
30 0
20 0
10 0

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

代码显然有问题。据我所知,它遵循所有语言规则,而且我似乎没有违反我能找到的关于比较函数或 set 的任何要求。但是 set 提供的保证仍然无效,这意味着我一定遗漏了什么。

最佳答案

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

... For any two keys k1 and k2 in the same container, calling comp(k1, k2) shall always return the same value.

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

关于c++ - 语言的哪一部分禁止更改 std::set 的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58420992/

相关文章:

std::vector 的 C++ 模板包装器类

C++ 对象创建或函数原型(prototype)声明

c++0x标准库引用手册

c - 中断对上下文的干扰有多大?如何恢复它?

c++ - 错误使用 std::copy?

c++ - 对std::vector使用嵌套的[]操作

c++ - OpenMP 和 NUMA 的关系?

c++ - CPropertySheet 只显示一秒钟

c++11 - clang++失败,但g++成功在赋值中使用强制转换为const-unrelated-type运算符

c - 使用 char * 访问 int 是否可能具有未定义的行为?