Jawaban:
Sederhana saja. Katakanlah saya punya vektor:
std::vector<int> vec;
Saya mengisinya dengan beberapa data. Lalu saya ingin mendapatkan beberapa iterator untuk itu. Mungkin melewati mereka. Mungkin untuk std::for_each:
std::for_each(vec.begin(), vec.end(), SomeFunctor());
Di C ++ 03, SomeFunctorbebas untuk dapat memodifikasi parameter yang didapatnya. Tentu, SomeFunctorbisa mengambil parameternya berdasarkan nilai atau const&, tetapi tidak ada cara untuk memastikannya . Bukan tanpa melakukan sesuatu yang konyol seperti ini:
const std::vector<int> &vec_ref = vec;
std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor());
Sekarang, kami memperkenalkan cbegin/cend:
std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());
Sekarang, kami memiliki jaminan sintaksis yang SomeFunctortidak dapat memodifikasi elemen-elemen vektor (tentu saja, tanpa menggunakan konstanta). Kami secara eksplisit mendapatkan const_iterators, dan karenanya SomeFunctor::operator()akan dipanggil dengan const int &. Jika parameter itu diambil sebagai int &, C ++ akan mengeluarkan kesalahan kompiler.
C ++ 17 memiliki solusi yang lebih elegan untuk masalah ini: std::as_const. Yah, setidaknya elegan saat menggunakan berbasis rentang for:
for(auto &item : std::as_const(vec))
Ini hanya mengembalikan a const&ke objek yang disediakan.
std::cbegin/cendfungsi gratis seperti yang std::begin/std::endada. Itu adalah pengawasan oleh komite. Jika fungsi-fungsi itu memang ada, itu biasanya akan menjadi cara untuk menggunakannya.
std::cbegin/cendakan ditambahkan dalam C ++ 14. Lihat en.cppreference.com/w/cpp/iterator/begin
for(auto &item : std::as_const(vec))setara dengan for(const auto &item : vec)?
constreferensi. Nicol memandang wadah sebagai const, jadi automenyimpulkan constreferensi. IMO auto const& itemlebih mudah dan lebih jelas. Tidak jelas mengapa std::as_const()bagus di sini; Saya bisa melihatnya akan berguna ketika melewati sesuatu yang bukan constuntuk kode generik di mana kita tidak bisa mengontrol tipe yang digunakan, tetapi dengan range- for, kita bisa, jadi sepertinya ada noise tambahan di sana.
Di luar apa yang dikatakan Nicol Bolas dalam jawabannya , pertimbangkan autokata kunci baru :
auto iterator = container.begin();
Dengan auto, tidak ada cara untuk memastikan bahwa begin()mengembalikan operator konstan untuk referensi kontainer tidak konstan. Jadi sekarang Anda lakukan:
auto const_iterator = container.cbegin();
const_iteratorhanyalah pengidentifikasi lain. Versi tidak menggunakan pencarian dari typedefs anggota biasa decltype(container)::iteratoratau decltype(container)::const_iterator.
const_iteratordengan auto: Menulis fungsi template tambahan yang disebut make_constlolos argumen objek.
Anggap ini sebagai usecase praktis
void SomeClass::f(const vector<int>& a) {
auto it = someNonConstMemberVector.begin();
...
it = a.begin();
...
}
Penugasan gagal karena itmerupakan iterator nonconst. Jika Anda menggunakan cbegin pada awalnya, iterator akan memiliki tipe yang tepat.
Dari http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf :
sehingga seorang programmer dapat langsung mendapatkan const_iterator bahkan dari wadah non-const
Mereka memberi contoh ini
vector<MyType> v;
// fill v ...
typedef vector<MyType>::iterator iter;
for( iter it = v.begin(); it != v.end(); ++it ) {
// use *it ...
}
Namun, ketika sebuah traversal kontainer hanya dimaksudkan untuk inspeksi, itu adalah praktik yang umumnya disukai untuk menggunakan const_iterator untuk mengizinkan kompiler untuk mendiagnosis pelanggaran konstitusionalitas.
Perhatikan bahwa kertas kerja juga menyebutkan template adaptor, yang sekarang telah selesai std::begin()dan std::end()dan juga bekerja dengan array asli. Yang sesuai std::cbegin()dan std::cend()anehnya hilang pada saat ini, tetapi mereka mungkin juga ditambahkan.
Baru saja menemukan pertanyaan ini ... Saya tahu itu sudah menjawab dan itu hanya simpul samping ...
auto const it = container.begin() adalah tipe yang berbeda auto it = container.cbegin()
perbedaan untuk int[5](menggunakan pointer, yang saya tahu tidak memiliki metode mulai tetapi menunjukkan dengan baik perbedaan ... tetapi akan bekerja di c ++ 14 untuk std::cbegin()dan std::cend(), yang pada dasarnya apa yang harus digunakan ketika ada di sini) ...
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
iteratordan const_iteratormemiliki hubungan pewarisan dan konversi implisit terjadi jika dibandingkan dengan atau ditugaskan ke jenis lainnya.
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)
{
// ...
}
Menggunakan cbegin()dan cend()akan meningkatkan kinerja dalam hal ini.
for (std::vector<T>::const_iterator it=MyVector.cbegin(); it!=MyVector.cend(); ++it)
{
// ...
}
constmanfaat utama adalah kinerja (yang bukan: itu kode yang secara semantik benar dan aman). Tapi, sementara Anda ada benarnya, (A) automembuat itu bukan masalah; (B) dalam berbicara tentang kinerja, Anda melewatkan hal utama yang harus Anda lakukan di sini: cache enditerator dengan mendeklarasikan salinannya dalam kondisi awal forloop, & bandingkan dengan itu, alih-alih mendapatkan salinan baru dengan nilai untuk setiap iterasi. Itu akan membuat poin Anda lebih baik. : P
constpasti dapat membantu mencapai kinerja yang lebih baik, bukan karena beberapa keajaiban dalam constkata kunci itu sendiri tetapi karena kompiler dapat mengaktifkan beberapa optimasi jika tahu bahwa data tidak akan dimodifikasi, yang tidak akan mungkin dilakukan sebaliknya. Periksa bit ini dari ceramah Jason Turner untuk contoh langsung tentang ini.
constdapat (hampir secara tidak langsung) mengarah pada manfaat kinerja; kalau-kalau seseorang membaca ini mungkin berpikir "Saya tidak akan repot menambahkan constjika kode yang dihasilkan tidak terpengaruh dengan cara apa pun", yang tidak benar.
sederhana, cbegin mengembalikan iterator konstan di mana mulai mengembalikan iterator
untuk pemahaman yang lebih baik mari kita ambil dua skenario di sini
skenario 1 :
#include <iostream>
using namespace std;
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<int> v;
for (int i = 1; i < 6; ++i)
{
/* code */
v.push_back(i);
}
for(auto i = v.begin();i< v.end();i++){
*i = *i + 5;
}
for (auto i = v.begin();i < v.end();i++){
cout<<*i<<" ";
}
return 0;
}
ini akan berjalan karena di sini iterator saya tidak konstan dan dapat bertambah 5
sekarang mari kita gunakan cbegin dan cend menunjukkan mereka sebagai skenario iterators konstan - 2:
#include <iostream>
using namespace std;
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<int> v;
for (int i = 1; i < 6; ++i)
{
/* code */
v.push_back(i);
}
for(auto i = v.cbegin();i< v.cend();i++){
*i = *i + 5;
}
for (auto i = v.begin();i < v.end();i++){
cout<<*i<<" ";
}
return 0;
}
ini tidak akan berhasil, karena Anda tidak dapat memperbarui nilai menggunakan cbegin dan cend yang mengembalikan iterator konstan