const auto&
sudah cukup jika saya ingin melakukan operasi hanya-baca. Namun, saya telah bertemu
for (auto&& e : v) // v is non-const
beberapa kali baru-baru ini. Ini membuat saya bertanya-tanya:
Mungkinkah dalam beberapa kasus sudut yang tidak jelas ada beberapa manfaat kinerja dalam menggunakan referensi penerusan, dibandingkan dengan auto&
atau const auto&
?
( shared_ptr
adalah tersangka untuk kasus sudut yang tidak jelas)
Perbarui Dua contoh yang saya temukan di favorit saya:
Adakah kerugian menggunakan referensi const saat melakukan iterasi pada tipe dasar?
Dapatkah saya dengan mudah mengulang nilai peta menggunakan for loop berbasis rentang?
Harap konsentrasikan pada pertanyaan: mengapa saya ingin menggunakan auto && in range-based for loop?
auto&&
loop berbasis jangkauan?Jawaban:
Satu-satunya keuntungan yang bisa saya lihat adalah ketika iterator urutan mengembalikan referensi proxy dan Anda perlu mengoperasikan referensi itu dengan cara non-const. Misalnya pertimbangkan:
Ini tidak dapat dikompilasi karena rvalue yang
vector<bool>::reference
dikembalikan dariiterator
tidak akan mengikat ke referensi lvalue non-const. Tapi ini akan berhasil:Semua yang dikatakan, saya tidak akan membuat kode dengan cara ini kecuali Anda tahu Anda perlu memenuhi kasus penggunaan seperti itu. Yaitu saya tidak akan melakukan ini cuma-cuma karena tidak menyebabkan orang bertanya-tanya apa yang Anda lakukan. Dan jika saya melakukannya, tidak ada salahnya untuk menyertakan komentar mengapa:
Sunting
Kasus terakhir saya ini harus benar-benar menjadi template yang masuk akal. Jika Anda tahu bahwa loop selalu menangani referensi proxy, maka itu
auto
akan berfungsi dengan baikauto&&
. Tetapi ketika loop terkadang menangani referensi non-proxy dan terkadang referensi proxy, maka saya pikirauto&&
akan menjadi solusi pilihan.sumber
const auto&
ketika saya ingin kompiler membantu saya memeriksa bahwa saya tidak sengaja mengubah elemen dalam urutan.auto&&
kode umum di mana saya perlu mengubah elemen urutan. Jika tidak, saya akan tetap berpegang padaauto const&
.Menggunakan
auto&&
atau referensi universal dengan range-basedfor
-loop memiliki keuntungan bahwa Anda menangkap apa yang Anda dapatkan. Untuk sebagian besar jenis iterator, Anda mungkin akan mendapatkan aT&
atau aT const&
untuk beberapa jenisT
. Kasus yang menarik adalah di mana dereferensi sebuah iterator menghasilkan sementara: C ++ 2011 mendapatkan persyaratan yang lebih longgar dan iterator tidak selalu diperlukan untuk menghasilkan nilai l. Penggunaan referensi universal cocok dengan penerusan argumen distd::for_each()
:Fungsi objek
f
dapat mengobatiT&
,T const&
danT
berbeda. Mengapa body dari range-basedfor
-loop berbeda? Tentu saja, untuk benar-benar memanfaatkan hasil deduksi tipe menggunakan referensi universal, Anda harus meneruskannya sesuai:Tentu saja, menggunakan
std::forward()
cara yang Anda terima dari nilai yang dikembalikan untuk dipindahkan. Apakah objek seperti ini masuk akal dalam kode non-template, saya belum tahu (belum?). Saya dapat membayangkan bahwa menggunakan referensi universal dapat menawarkan lebih banyak informasi kepada kompiler untuk melakukan Hal yang Benar. Dalam kode templated, ia tidak membuat keputusan apa pun tentang apa yang harus terjadi dengan objek.sumber
Saya hampir selalu menggunakan
auto&&
. Mengapa digigit oleh kasus tepi saat Anda tidak perlu? Ini juga lebih pendek untuk diketik, dan saya merasa lebih ... transparan. Saat Anda menggunakanauto&& x
, maka Anda tahux
persis*it
, setiap saat.sumber
const
denganauto&&
jikaconst auto&
sudah cukup. Pertanyaannya menanyakan kasus sudut di mana saya bisa digigit. Apa kasus sudut yang belum disebutkan oleh Dietmar atau Howard?auto&&
. Jika jenis yang Anda tangkap harus dipindahkan di badan perulangan (misalnya), dan diubah ke tanggal yang akan datang sehingga ditetapkan keconst&
jenis, kode Anda akan terus berfungsi secara diam-diam, tetapi gerakan Anda akan menjadi salinan. Kode ini akan sangat menipu. Namun, jika Anda secara eksplisit menetapkan jenis sebagai referensi nilai-r, siapa pun yang mengubah jenis penampung akan mendapatkan kesalahan kompilasi karena Anda benar-benar ingin objek ini dipindahkan dan tidak disalin ...for (std::decay_t<decltype(*v.begin())>&& e: v)
? Saya kira ada cara yang lebih baik ...auto&&
akan memberikan "referensi universal", jadi apa pun selain itu akan memberi Anda tipe yang lebih spesifik. Jikav
diasumsikan avector
, Anda bisa melakukandecltype(v)::value_type&&
, yang saya asumsikan Anda inginkan dengan mengambil hasil darioperator*
pada tipe iterator. Anda juga bisa melakukandecltype(begin(v))::value_type&&
untuk memeriksa jenis iterator sebagai ganti wadahnya. Namun, jika kita memiliki sedikit wawasan tentang jenisnya, kita mungkin menganggapnya sedikit lebih jelas untuk hanya menggunakanauto&&
...