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

And*_*rey 182 c++ iterator const-correctness const-iterator c++11

我想知道为什么cbegincend在C++ 11中引入?

什么情况下使用这些方法时,使得从常量重载的差异beginend

Nic*_*las 220

这很简单.说我有一个矢量:

std::vector<int> vec;
Run Code Online (Sandbox Code Playgroud)

我填写了一些数据.然后我想得到一些迭代器.也许传递给他们.也许到std::for_each:

std::for_each(vec.begin(), vec.end(), SomeFunctor());
Run Code Online (Sandbox Code Playgroud)

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

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

现在,我们介​​绍cbegin/cend:

std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());
Run Code Online (Sandbox Code Playgroud)

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


C++ 17有一个更优雅的解决方案来解决这个问题:std::as_const.好吧,至少在使用基于范围时它很优雅for:

for(auto &item : std::as_const(vec))
Run Code Online (Sandbox Code Playgroud)

这只是将a返回const&给它提供的对象.

  • @Kaz:`std :: begin/std :: end`的存在方式没有`std :: cbegin/cend`自由函数.这是委员会的疏忽.如果这些功能确实存在,那通常就是使用它们的方式. (19认同)
  • 显然,`std :: cbegin/cend`将在C++ 14中添加.见http://en.cppreference.com/w/cpp/iterator/begin (19认同)
  • @NicolBolas是`for(auto&item:std :: as_const(vec))`相当于`for(const auto&item:vec)`? (7认同)
  • @luizfls是的.您的代码表示不会通过将`const`放在引用上来修改该项.Nicol将容器视为const,因此`auto`推导出一个`const`引用.IMO`auto const&item`更容易,更清晰.目前还不清楚为什么`std :: as_const()`在这里很好; 我可以看到它在将非`constst'传递给通用代​​码时非常有用,我们无法控制使用的类型,但是使用range-`for`,我们可以,所以它似乎只是增加了噪音我在那里. (7认同)

Ste*_*sky 65

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

auto iterator = container.begin();
Run Code Online (Sandbox Code Playgroud)

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

auto const_iterator = container.cbegin();
Run Code Online (Sandbox Code Playgroud)

  • @allyourcode:这会给你一个常量的迭代器,但这与迭代器到常量数据非常不同. (26认同)
  • 也许我不再处于C++思维模式中了,但我看不出"简单方法"和"编写辅助功能模板"概念之间的联系.;) (15认同)
  • @allyourcode:没有帮助.对于编译器,`const_iterator`只是另一个标识符.这两个版本都没有使用通常的成员typedef`decltype(container):: iterator`或`decltype(container):: const_iterator`的查找. (2认同)
  • @aschepler我不明白你的第二句话,但我认为你在我的问题中错过了"auto"前面的"const".无论什么自动来,似乎const_iterator应该是const. (2认同)
  • 有一种简单的方法可以确保你使用`auto`获得`const_iterator`:编写一个名为`make_const`的辅助函数模板来限定object参数. (2认同)
  • @Columbo:为什么写一个,现在有[`std :: as_const`](http://en.cppreference.com/w/cpp/utility/as_const).所以`std :: as_const(vec).begin()`和`vec.cbegin()`是等价的 (2认同)

Joh*_*itb 14

把它作为一个实用的用例

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

赋值失败,因为它it是一个非对象迭代器.如果你最初使用了cbegin,迭代器就会有正确的类型.


Tem*_*Rex 8

来自http://www.open-std.org/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 ...
}
Run Code Online (Sandbox Code Playgroud)

但是,当容器遍历仅用于检查时,通常优选使用const_iterator以允许编译器诊断const-correctness违规

请注意,工作文件还提到了适配器模板,现在已经最终确定为std::begin(),std::end()并且也适用于本机阵列.相应的,std::cbegin()并且std::cend()在这个时候奇怪地丢失了,但是它们也可能被添加.


chr*_* g. 5

只是偶然发现了这个问题...我知道它已经被回答了,而且只是一个副节点...

auto const it = container.begin() 然后是另一种类型 auto it = container.cbegin()

的区别int[5](使用指针,我知道没有begin方法,但是很好地显示了区别...但是可以在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
Run Code Online (Sandbox Code Playgroud)