为什么 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
是因为它们不允许您更改基础值,而不是容器本身。您仍然需要有一个非常量列表来插入元素,因为 insert
是 std::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
}
为什么STL容器可以使用const_iterator
插入?比如有
iterator std::list::insert (const_iterator position, const value_type& val);
我以为const_iterator
不允许修改容器。
它们被称为 const_iterator
是因为它们不允许您更改基础值,而不是容器本身。您仍然需要有一个非常量列表来插入元素,因为 insert
是 std::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 library23.2.3, 23.2.4
Change: Signature changes: from
iterator
toconst_iterator
parameters
Rationale: Overspecification.
Effects: The signatures of the following member functions changed from taking aniterator
to taking aconst_iterator
:
insert(iter, val)
forvector
,deque
,list
,set
,multiset
,map
,multimap
insert(pos, beg, end)
forvector
,deque
,list
,forward_list
erase(iter)
forset
,multiset
,map
,multimap
erase(begin, end)
forset
,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 aconst_iterator
in C++0x. This breaks code where the map'skey_type
has a constructor which accepts an iterator (for example a template constructor), as the compiler cannot choose betweenerase(const key_type&)
anderase(const_iterator)
.
当一个元素被插入到列表中时,其他元素没有被修改。迭代器仅用于确定插入位置,不用于修改(=在上调用非常量成员函数)任何现有元素。
连erase
都可以拿const_iterator
。同样,这是因为 擦除元素也不会修改它 。这听起来可能很奇怪,但如果你考虑一下,这就微不足道了:
void f()
{
std::string const s = "foo";
// the function ends and s is destroyed even though it was constant
}