Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 语言的哪一部分禁止更改std::set的元素_C++_Language Lawyer_Std_Stdset_Invariants - Fatal编程技术网

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

C++ 语言的哪一部分禁止更改std::set的元素,c++,language-lawyer,std,stdset,invariants,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 { bo

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);
}
表达式
值[1]=0
有效地间接更改
集合
的一个键。这破坏了顺序,因此似乎也破坏了计数。我认为这也会破坏
集合的大部分其他功能


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

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

。。。对于同一容器中的任意两个键
k1
k2
,调用
comp(k1,k2)
应始终返回相同的值


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

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

。。。对于同一容器中的任意两个键
k1
k2
,调用
comp(k1,k2)
应始终返回相同的值


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

[政治上不太正确的备注:标准中有很多东西是不成文的,甚至有些东西是不正确的。您必须弥补缺失的部分,这比解析精确的单词更可靠。]

所有关联容器(已排序或未排序)都基于公理化需求

隐式基础是,所有有公理的谓词/函子都是数学关系/函数,否则公理不可能有任何意义显然,这些函数,比如比较器,必须定义得很好;这意味着容器中当前的元素是有序的


但是,如果您的容器是空的,并且您更改了它的排序函数,这并不重要。您还可以使用极轴排序,根据角度对元素进行排序,并使用任意截断(定义为最小角度),如果旋转未通过容器中的元素,则旋转该最小角度线。

[政治上不太正确的评论:标准中有很多东西是不成文的,甚至书面的东西有时也不正确。你必须弥补缺失的部分,这比解析准确的单词更可靠。]

所有关联容器(已排序或未排序)都基于公理化需求

隐式基础是,所有存在公理的谓词/函子都是数学关系/函数,否则公理不可能有任何意义。因此显然,这些函数,如比较器,必须定义良好;这意味着容器中当前的元素是有序的


但不管容器是否为空,也可以更改其排序函数。也可以使用极轴排序,根据角度对元素进行排序,并使用任意截断(定义为最小角度),并旋转该最小角度线,如果旋转未通过容器中的元素。

这一切归结为标准在其生命周期([basic.life])内修改常量对象([basic.type.qualifier])的任何尝试([expr.ass]、[expr.post.incr]、[expr.pre.incr])的意思导致未定义的行为。对我来说,这说明它是合法的。但理想情况下,我希望它不是。@NathanOliver哪个
const
对象正在被修改?编辑:但我同意这个定义对我来说似乎很弱。@HTNW注意,容器不是
const
,我的标题是指contai的
const
元素但是现在我发现它还不清楚。@FrançoisAndrieux None,这就是问题所在。你所指的东西不被认为是指针状态的一部分。看起来这不是一个很好的例子,因为Brian的回答指出关联容器明确地涵盖了这个场景。这一切归结为标准在任何试图在常量对象([basic.type.qualifier])的生存期([basic.life])内修改([expr.ass]、[expr.post.incr]、[expr.pre.incr])的行为导致未定义的行为。对我来说,这说明它是合法的。但理想情况下,我希望它不是。@NathanOliver哪个
const
对象正在被修改?编辑:但我同意这个定义对我来说似乎很弱。@HTNW注意,容器不是
const
,我的标题是指contai的
const
元素但是现在我看不清楚了。@FrançoisAndrieux None,这就是问题所在。你所指的东西不被视为指针状态的一部分。看起来这不是一个很好的例子,因为Brian的回答指出关联容器明确地涵盖了这个场景。
50 1
40 1
30 1
20 1
10 1

50 1
0 0
30 0
20 0
10 0