我想知道为什么在c++ 11中引入cbegin和cend ?

在什么情况下,调用这些方法与const重载begin和end有区别?


当前回答

从http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf:

这样程序员就可以直接从 non-const容器

他们举了这个例子

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::cend()到目前为止都没有,但它们也可能被添加。

其他回答

除了Nicol Bolas在他的回答中所说的,考虑一下新的auto关键字:

auto iterator = container.begin();

使用auto,无法确保begin()为非常量容器引用返回常量操作符。所以现在你知道了:

auto const_iterator = container.cbegin();

从http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf:

这样程序员就可以直接从 non-const容器

他们举了这个例子

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::cend()到目前为止都没有,但它们也可能被添加。

将此作为一个实际用例

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

赋值失败是因为它是非const迭代器。如果一开始使用cbegin,迭代器的类型就正确了。

只是偶然发现了这个问题……我知道它已经是答案了,它只是一个侧节点。

Auto const it = container.begin()是另一种类型Auto it = container.cbegin()

int[5]的区别(使用指针,我知道没有开始方法,但很好地显示了区别……但是在c++14中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

这很简单。假设我有一个向量:

std::vector<int> vec;

我用一些数据填充它。然后我想给它一些迭代器。也许可以传阅一下。可能是std::for_each:

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

在c++ 03中,SomeFunctor可以自由地修改它得到的参数。当然,SomeFunctor可以通过value或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不能修改vector的元素(当然,没有使用const-cast)。我们显式地获取const_iterators,因此SomeFunctor::operator()将被const int &调用。如果它的参数为int &, c++将发出编译器错误。


c++ 17对这个问题有一个更优雅的解决方案:std::as_const。好吧,至少它在使用range-based for时很优雅:

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

这只是向所提供的对象返回一个const&。