cbegin / cend背后的原因是什么?

我想知道为什么cbegincbegin是在C ++ 11中引入的?

什么情况下调用这些方法与const的重载beginend什么不同?

这很简单。 说我有一个vector:

 std::vector<int> vec; 

我填写一些数据。 然后我想获得一些迭代器。 也许可以绕过他们。 也许是std::for_each

 std::for_each(vec.begin(), vec.end(), SomeFunctor()); 

在C ++ 03中, SomeFunctor可以自由地修改它获取的参数。 当然, SomeFunctor可以通过值或const&来接受它的参数,但是没有办法确保它的确如此。 不是没有做这样愚蠢的事情:

 const std::vector<int> &vec_ref = vec; std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor()); 

现在我们介绍一下cbegin/cend

 std::for_each(vec.cbegin(), vec.cend(), SomeFunctor()); 

现在,我们有句法保证SomeFunctor不能修改向量的元素(当然没有const-cast)。 我们明确地得到了const_iterator ,因此SomeFunctor :: operator()将会被const int &调用。 如果将参数作为int & ,C ++将发出编译器错误。


C ++ 17有一个更优雅的解决scheme: std::as_const 。 那么,至less在使用基于范围的情况下,它是优雅for

 for(auto &item : std::as_const(vec)) 

这只是返回一个const&到它提供的对象。

除了尼古拉·布拉斯(Nicol Bolas)在他的回答中所说的,考虑一下新的auto关键字:

 auto iterator = container.begin(); 

对于auto ,没有办法确保begin()为一个非常量容器引用返回一个常量运算符。 所以现在你做:

 auto const_iterator = container.cbegin(); 

把这作为一个实际的用例

 void SomeClass::f(const vector<int>& a) { auto it = someNonConstMemberVector.begin(); ... it = a.begin(); ... } 

分配失败,因为it是一个nonconst迭代器。 如果你最初使用cbegin,那么迭代器就会有正确的types。

jtc1/sc22/wg21/docs/papers/2004/n1674.pdf

所以程序员甚至可以从一个非const容器中直接获得一个const_iterator

他们给了这个例子

 vector<MyType> v; // fill v ... typedef vector<MyType>::iterator iter; for( iter it = v.begin(); it != v.end(); ++it ) { // use *it ... } 

然而,当一个容器遍历仅用于检查时,通常使用一个const_iterator来允许编译器诊断常量正确性违规

请注意,工作文件还提到了适配器模板,现在已经定稿为std::begin()std::end() ,并且也适用于本机数组。 std::cbegin() ,相应的std::cbegin()std::cbegin()很好奇地丢失了,但是它们也可能被添加。

刚刚偶然发现了这个问题…我知道这是答案,它只是一个边节点…

auto const it = container.begin()是一个不同的types,然后auto it = container.cbegin()

int[5]的差别(使用指针,我知道没有开始的方法,但很好地显示差异…但将工作在C ++ 14为std::cbegin()std::cend() std::cbegin() std::cend() ,这本质上是在这里应该使用的)…

 int numbers = array[7]; const auto it = begin(numbers); // type is int* const -> pointer is const auto it = cbegin(numbers); // type is int const* -> value is const 

iteratorconst_iterator具有inheritance关系,并且与其他types进行比较或分配时发生隐式转换。

 class T {} MyT1, MyT2, MyT3; std::vector<T> MyVector = {MyT1, MyT2, MyT3}; for (std::vector<T>::const_iterator it=MyVector.begin(); it!=MyVector.end(); ++it) { // ... } 

在这种情况下使用cbegin()cbegin()会提高性能。

 for (std::vector<T>::const_iterator it=MyVector.cbegin(); it!=MyVector.cend(); ++it) { // ... }