2014-09-11 47 views
18

来自Scott Mayers的“Effective STL”的项目26被标记为“优选iteratorconst_iterator,reverse_iteratorconst reverse iterator”。常量迭代器在C++中仍然是邪恶的14

推理原因是insert()erase()的某些形式需要使用iterator,而从其他类型转换是繁琐且容易出错的。此外,根据STL的实现,比较iteratorconst_iterator可能会有问题。

该书于2001年发布。第26条中的建议是否仍然适用于当前的gcc状态?

+2

当然'insert'和'erase'需要一个非const的'iterator':他们改变数据,所以'const'数据将是一个坏主意。 – gexicide 2014-09-11 09:12:49

+14

@gexicide:错了。如果你可以调用'erase',无论如何你都可以访问容器。出于这个原因,C++ 11改变了'erase'和'insert'函数来取'const_iterator's('iterator's总是可以转换为它们的'const_'变体)。 – Xeo 2014-09-11 09:14:05

+0

@Xeo:对,我的错。感谢您清理它。 – gexicide 2014-09-11 09:15:06

回答

18

的C++ 14标准(N3936)保证iteratorconst_iterator可自由相当(§23.2.1[container.requirements.general]/P7):

在表达式

i == j 
i != j 
i < j 
i <= j 
i >= j 
i > j 
i - j 

其中容器的iterator类型的ij分别表示的对象, 任一个或两个可通过所述容器的 const_iterator类型refe的目的来代替转向相同的元素,但语义不变。

此外,容器的成员函数采取const_iterator参数的C++ 11(§C.2.13[diff.cpp03.containers] - 作为可能会从标签可以推断,这是从C变更+ 03):

变化:签名的变化:从iteratorconst_iterator参数

理由:Overspecification。 影响:下列成员函数的签名从服用iterator改变为服用 一个const_iterator

  • insert(iter, val)vectordequelistsetmultisetmapmultimap
  • insert(pos, beg, end)vectordeque, list, forward_list
  • erase(iter) for设置,多重集,地图, multimap`
  • erase(begin, end) for设置,多重集,地图, multimap`
  • 所有形式的list::splice
  • 所有形式的list::merge

容器要求已被类似地改变采用常量迭代器。此外,通过.base()成员函数可以很容易地从std::reverse_iterator获取底层迭代器。因此,问题中提到的问题都不应该成为合格编译器的问题。

+3

您应该明确提到这是已经从C++ 03 - > C++ 11进行的更改。 – Xeo 2014-09-11 09:33:17

+0

关于具有.base的反向迭代器的说明也不错。 – Puppy 2014-09-11 09:33:30

7

的建议已被颠倒,如可以从该标题为即将到来的Effective Modern C++的项目13中可以看出:

不想const_iterators到迭代器

其原因是,C++ 11和C++ 14增加若干调整,使const_iterators很多更实用:

C++ 11增加

  • 所有标准库容器的成员函数cbegin()cend()(及其反向对应项)
  • 使用迭代器标识位置的成员函数(例如, insert()erase())现在来const_iterator代替iterator

C++ 14完成,通过添加非成员cbegin()cend()(和它们的反转对应物)