为什么 STL 容器可以使用 const 迭代器插入

Why STL containers can insert using const iterator

为什么STL容器可以使用const_iterator插入?比如有

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

我以为const_iterator不允许修改容器。

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

假设您有一个函数可以让您找到并 iterator 某个元素。它不需要更改任何内容,因此您将其设计为 return const_iterator。然后您想在此迭代器中插入 list,但如果 list 的接口受到更多限制,那么您将无法插入。

"I have thought that const_iterator's does not allow to modify container."

你应该注意到

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

实际上是std::list的非const成员函数。
您仍然需要一个可变的 std::list 实例来应用它,容器不会通过迭代器修改。 position 参数,只是指定插入新值的位置。

除了 Spo1ler 的回答之外,请注意 C++11 更改了一堆库函数来精确地执行此操作:

[C++11: C.2.12]: Clause 23: containers library

23.2.3, 23.2.4

Change: Signature changes: from iterator to const_iterator parameters
Rationale: Overspecification.
Effects: The signatures of the following member functions changed from taking an iterator to taking a const_iterator:

  • insert(iter, val) for vector, deque, list, set, multiset, map, multimap
  • insert(pos, beg, end) for vector, deque, list, forward_list
  • erase(iter) for set, multiset, map, multimap
  • erase(begin, end) for set, multiset, map, multimap
  • all forms of list::splice
  • all forms of list::merge

Valid C++ 2003 code that uses these functions may fail to compile with this International Standard.

例如:

他们这样做是因为他们最初假设了你的做法,但后来意识到这没有什么意义,而且无缘无故地让人头疼。 "overspecified".

A const_iterator 有助于在遍历范围时保证 element 不变性,但如果这也意味着您不能使用它来进行限制,那将是不必要的限制描述容器中执行突变的位置。如果您需要这两种行为,您始终可以让容器本身在该范围内 const

不过需要注意的是this change isn't universally liked, because:

map::erase (and several related methods) took an iterator in C++03, but take a const_iterator in C++0x. This breaks code where the map's key_type has a constructor which accepts an iterator (for example a template constructor), as the compiler cannot choose between erase(const key_type&) and erase(const_iterator).

当一个元素被插入到列表中时,其他元素没有被修改。迭代器仅用于确定插入位置,不用于修改(=上调用非常量成员函数)任何现有元素。

erase都可以拿const_iterator。同样,这是因为 擦除元素也不会修改它 。这听起来可能很奇怪,但如果你考虑一下,这就微不足道了:

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