通过迭代器分配给元素

Assigning to an element via iterator

我认为我们可以通过其 非常量 迭代器为容器的元素分配一个新值。所以我试了一下:

#include<iostream>
#include<set>

typedef std::set<int>::iterator it;

std::set<int> set_int;

int main()
{ 
    set_int.insert(1);
    it i = set_int.begin();
    *i = 11;  //error: assignment of read-only location
}

失败了。为什么我失败了?

根据标准N4431 §23.2.4/6 关联容器[associative.reqmts]强调我的):

关联容器的

iterator 属于双向迭代器类别。 对于值类型与键类型相同的关联容器,迭代器和const_iterator都是常量迭代器。是 未指定 iterator 和 const_iterator 是否为同一类型。 [ 注意:iteratorconst_-iterator 在这种情况下具有相同的语义,并且 iterator 可转换为 const_iterator。用户可以通过始终在其函数参数列表中使用 const_iterator 来避免违反单一定义规则。— 尾注 ].

std::set 是一个关联容器,其值类型与键类型相同,因此,std::set<T>::iterator 是一个常量迭代器。因此,您遇到的失败是有道理的。

A set 实际上没有非 const 迭代器,因为它的元素是不可变的。如果您考虑一下,假设您通过迭代器更改密钥。为什么 poor set 会四处移动节点以保持树不变量等等?

有关更详细、更细致的讨论,请参阅 Angelika Langer 的 this piece

std::set 在内部保持元素的顺序。它基本上是一个红黑树二进制实现,并使用 std::less<> 作为其默认比较器。因此,如果我按如下方式稍微修改您的示例:

    typedef std::set<int>::iterator it;
    std::set<int> set_int;
    set_int.insert(1);
    set_int.insert(6); //I added 
    it i = set_int.begin(); //error: assignment of read-only location
    *i = 11;

11 无法放入您的 std::set 容器的第一个迭代器位置,因为它违反了它的顺序。

所以很明显我们不能使用 std::set 的迭代器取消引用来更新元素。编译器不允许,你会得到编译错误。