なぜcbegin
とcend
がC++ 11で導入されたのだろうか?
これらのメソッドを呼び出すと、begin
およびend
のconstオーバーロードとは異なる場合はどうなりますか?
とても簡単です。ベクトルがあるとしましょう:
std::vector<int> vec;
いくつかのデータを入力します。次に、イテレータを取得します。たぶんそれらを渡します。多分std::for_each
に:
std::for_each(vec.begin(), vec.end(), SomeFunctor());
C++ 03では、SomeFunctor
は、取得したパラメーターをmodifyできるようになりました。確かに、SomeFunctor
は値またはconst&
でパラメーターを取ることができますが、それをensureする方法はありません。このような愚かなことをせずに:
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キャストなしで)。 const_iterator
sを明示的に取得するため、SomeFunctor::operator()
はconst int &
で呼び出されます。 int &
としてパラメータを取る場合、C++はコンパイラエラーを発行します。
C++ 17には、この問題に対するよりエレガントなソリューションがあります: std::as_const
。少なくとも、範囲ベースの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
は非定数反復子であるため、割り当ては失敗します。最初にcbeginを使用した場合、イテレーターのタイプは適切でした。
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 ...
}
ただし、コンテナトラバーサルが検査のみを目的としている場合、コンパイラがconst-correctness違反を診断できるようにするために、const_iteratorを使用することをお勧めします。
ワーキングペーパーではアダプターテンプレートについても言及していることに注意してください。アダプターテンプレートはstd::begin()
およびstd::end()
として確定されており、ネイティブ配列でも機能します。現時点では、対応するstd::cbegin()
とstd::cend()
は不思議なことに欠落していますが、追加される可能性もあります。
この質問につまずいた...私はそれがすでに答えられていることを知っています、それは単なるサイドノードです...
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
iterator
とconst_iterator
には継承関係があり、他の型と比較したり他の型に割り当てたりすると暗黙的な変換が発生します。
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()
およびcend()
を使用するとパフォーマンスが向上します。
for (std::vector<T>::const_iterator it=MyVector.cbegin(); it!=MyVector.cend(); ++it)
{
// ...
}