C++ 为什么STL容器可以使用常量迭代器插入

C++ 为什么STL容器可以使用常量迭代器插入,c++,stl,iterator,constants,C++,Stl,Iterator,Constants,为什么STL容器可以使用常量迭代器插入?例如,有 iterator std::list::insert (const_iterator position, const value_type& val); 我认为常量迭代器不允许修改容器。它们被称为常量迭代器s,因为它们不允许更改基础值,而不允许更改容器本身。您仍然需要有一个非常量列表来插入元素,因为insert是std::list的非常量成员,但接口是以限制最少的方式创建的 假设您有一个函数,该函数允许您查找某个元素并将其作为迭代器。它

为什么STL容器可以使用
常量迭代器插入?例如,有

iterator std::list::insert (const_iterator position, const value_type& val);

我认为
常量迭代器
不允许修改容器。

它们被称为
常量迭代器
s,因为它们不允许更改基础值,而不允许更改容器本身。您仍然需要有一个非常量列表来插入元素,因为
insert
std::list
的非常量成员,但接口是以限制最少的方式创建的

假设您有一个函数,该函数允许您查找某个元素并将其作为迭代器。它不需要更改任何内容,因此您可以将其设计为返回
const\u iterator
。然后您想在这个迭代器中插入到
列表
,但是如果
列表
的接口比它更受限制,您将无法插入

“我认为常量迭代器不允许修改容器。”

你应该注意到

iterator std::list::insert (const_iterator position, const value_type& val);
         // ^^^^^^
实际上是的非常量成员函数。

您仍然需要一个可变的
std::list
实例来应用它,容器不会通过迭代器进行修改。
position
参数只指定在何处插入新值。

除了Spo1ler的答案外,请注意C++11更改了一系列库函数,以精确执行此操作:

[C++11:C.2.12]:
第23条:容器库

23.2.3、23.2.4

更改:签名更改:从
迭代器
更改为
常量迭代器
参数
理由:规格过高。
效果:以下成员函数的签名从使用
迭代器
更改为使用
常量迭代器

  • insert(iter,val)
    用于
    向量
    deque
    列表
    集合
    多集
    映射
    多映射
  • 插入(pos,beg,end)
    用于
    向量
    deque
    列表
    转发列表
  • erase(iter)
    用于
    set
    multiset
    map
    multimap
  • 擦除(开始,结束)
    对于
    设置
    多集
    映射
    多映射
  • 所有形式的
    列表::拼接
  • 所有形式的
    list::merge

使用这些函数的有效C++ 2003代码可能无法用这个国际标准编译。 例如:

他们这样做是因为他们最初以为你是这样做的,但后来意识到这毫无意义,无缘无故地让人头痛。这是“过度指定的”

const_迭代器
有助于在范围内迭代时保证元素的不变性,但如果它也意味着您不能使用它来描述容器中执行变异的位置,那么它将是不必要的限制。如果需要这两种行为,则可以始终使容器本身在该范围内保持
const

但应注意的是:

map::erase
(以及一些相关方法)在C++03中使用了迭代器,但在C++0x中使用了
const_迭代器。当映射的
key\u type
具有接受迭代器的构造函数(例如模板构造函数)时,这会中断代码,因为编译器无法在
erase(const key\u type&)
erase(const\u迭代器)
之间进行选择


将元素插入列表时,不会修改其他元素。迭代器仅用于确定插入位置,而不是修改(=调用非常量成员函数)任何现有元素

即使是
擦除
也可以使用
常量迭代器
。同样,这是因为擦除元素也不会修改它。这听起来很奇怪,但如果你考虑到这一点,那就太微不足道了:

void f()
{
    std::string const s = "foo";
    // the function ends and s is destroyed even though it was constant
}

我喜欢这个例子。起初我犹豫不决,但实际上这是一个类比。再看一眼,阿尔夫的例子几乎是一样的,即使说得不那么清楚。