Haruskah saya menggunakan fitur 'otomatis' C ++ 11 yang baru, terutama dalam loop?

20

Apa pro / kontra untuk menggunakan autokata kunci, terutama untuk loop?

for(std::vector<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->something();
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->second->something();
}

for(auto it = x.begin(); it != x.end(); it++ )
{
   it->??
}

Sepertinya jika Anda tidak tahu apakah Anda memiliki iterator untuk peta atau vektor Anda tidak akan tahu apakah akan digunakan firstatau secondatau hanya langsung akses properti dari objek, tidak ada?

Ini mengingatkan saya pada perdebatan C # tentang apakah akan menggunakan kata kunci var. Kesan yang saya dapatkan sejauh ini adalah bahwa di dunia C ++ orang siap untuk mengadopsi autokata kunci dengan sedikit perkelahian daripada vardi dunia C #. Bagi saya insting pertama saya adalah saya suka mengetahui jenis variabelnya sehingga saya bisa tahu operasi apa yang dapat saya lakukan untuk melakukannya.

Pengguna
sumber
3
Tunggu! Ada pertengkaran tentang apakah akan digunakan var? Saya melewatkan itu.
pdr
21
Bahkan lebih baik, Anda bisa menggunakan for (auto& it : x)(atau tanpa referensi jika Anda ingin menyalin)
Tamás Szelei
7
Menurut saya jika Anda menulis satu loop untuk mengulangi isi dari xdan Anda bahkan tidak tahu apa xitu, Anda seharusnya tidak menulis loop itu di tempat pertama ;-)
nikie
@fish: aturan for-loop berbasis rentang, tapi saya akan menjadi bertele-tele dan selesai: 'for (T & it: x)' sebagai gantinya ketika menggunakan rentang untuk for-loop, karena saya merasa menggunakan otomatis ada yang kurang informatif. Semacam penyalahgunaan otomatis dalam pikiran saya.
martiert
Pertarungan menggunakan var sedikit konyol, terutama jika dipikir-pikir. Lihat pemrograman pemujaan kargo .
Craig

Jawaban:

38

Motivasi dalam C ++ lebih ekstrim, karena tipe bisa menjadi jauh lebih berbelit-belit dan kompleks daripada tipe C # karena metaprogramming dan hal-hal lain. autolebih cepat untuk menulis dan membaca dan lebih fleksibel / dipelihara daripada jenis eksplisit. Maksud saya, apakah Anda ingin mulai mengetik

boost::multi_map<NodeType, indexed_by<ordered_unique<identity<NodeType>>, hashed_non_unique<identity<NodeType>, custom_hasher>>::iterator_type<0> it

Itu bahkan bukan tipe lengkap. Saya melewatkan beberapa argumen templat.

DeadMG
sumber
8
+1 sebagai contoh, tetapi itu juga memberi tahu sesuatu tentang keadaan "modern" C ++.
zvrba
22
@ zvrba: Ya- bahwa fasilitas umum jauh lebih kuat daripada C #.
DeadMG
4
itulah gunanya typedef
gbjbaanb
19
@ gbjbaanb Tidak, itu untuk apa auto. Dengan desain. typedefmembantu, tetapi automembantu lebih banyak.
Konrad Rudolph
1
typedef mematahkan argumen bahwa "tidak menggunakan auto membuat untuk tipe yang sangat panjang"
Michael
28

Dalam contoh Anda:

for(auto it = x.begin(); it != x.end(); i++)
{
  it->??
}

harus ada deklarasi agar xterlihat. Karena itu jenisnya itharus jelas. Jika jenisnya xtidak jelas, maka metodenya terlalu panjang, atau kelasnya terlalu besar.

kevin cline
sumber
7
Juga, xnama variabel yang sangat buruk untuk sebuah wadah. Dalam beberapa situasi Anda kemungkinan besar hanya dapat melihat nama (bernilai semantik) dan menyimpulkan operasi yang mungkin.
Maks.
@ Max: hanya digunakan xsebagai contoh umum, saya cenderung menggunakan nama variabel yang cukup deskriptif.
Pengguna
@ Pengguna Tentu saja, saya tidak menganggap itu adalah contoh dunia nyata;)
Max
14

Keberatan ! Pertanyaan yang dimuat.

Bisakah Anda menjelaskan kepada saya mengapa kode ketiga ada ??di dalamnya, namun yang pertama dan kedua tidak? Demi keadilan, kode Anda harus dibaca sebagai berikut:

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->???
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->second->???
}

Sana. Masalah yang sama meskipun Anda tidak menggunakannya auto.

Dan dalam semua kasus, jawabannya sama: Konteks penting . Anda tidak dapat berbicara secara bermakna tentang sepotong kode secara terpisah. Bahkan jika Anda tidak menggunakan template tetapi beberapa tipe konkret, ini hanya akan memindahkan masalah ke tempat lain, karena pembaca kode Anda harus tahu tentang deklarasi tipe tersebut.

Jika penggunaan autodalam situasi itu membuat kode Anda tidak dapat dibaca, Anda harus memperlakukan ini sebagai tanda peringatan bahwa ada sesuatu yang salah dengan desain kode Anda. Tentu saja, ada kasus-kasus di mana rincian tingkat rendah penting (seperti ketika berhadapan dengan operasi bit atau legacy API) di mana kasus tipe eksplisit dapat membantu keterbacaan. Namun secara umum - tidak.

Mengenai var(karena Anda menyebutkannya secara eksplisit), ada juga konsensus luas dalam komunitas C # untuk digunakan var. Argumen yang menentang penggunaannya umumnya dibangun di atas kekeliruan .

Konrad Rudolph
sumber
1
Saya pikir intinya adalah, dengan otomatis Anda tidak tahu apa yang Anda masukkan selanjutnya ... apakah itu kode Anda "sesuatu" atau itu tipe data yang terkait membongkar untuk sampai ke objek data Anda yang memiliki metode "sesuatu"
Michael Shaw
1
@ Poltemy Dan poin saya adalah: dalam dua kode lainnya Anda juga tidak tahu (umumnya) apa yang akan dimasukkan selanjutnya: Tsama buramnya dengan pengguna auto. Namun yang satu seharusnya baik-baik saja dan yang lainnya tidak ?! Itu tidak masuk akal. Dalam kasus OP, Tadalah stand-in untuk tipe yang sewenang-wenang. Dalam kode nyata, mungkin penggunaan templat (for typename std::vector<T>::iterator…)atau antarmuka kelas. Dalam kedua kasus, tipe aktual disembunyikan dari pengguna, namun kami secara rutin menulis kode seperti itu tanpa masalah.
Konrad Rudolph
1
Sebenarnya ya. Jika ini adalah vektor, Anda tahu yang perlu Anda lakukan -> dan kemudian Anda memiliki akses ke tipe data Anda. Jika ini peta, Anda tahu harus melakukan -> kedua-> dan kemudian Anda memiliki akses ke tipe data Anda, jika itu otomatis, Anda tidak tahu apa yang perlu Anda lakukan untuk mendapatkan akses ke tipe data Anda. Anda tampaknya membingungkan "apa tipe data yang terkandung dalam koleksi STL" dengan "jenis koleksi STL yang kita miliki". otomatis membuat masalah ini lebih buruk.
Michael Shaw
1
@Ptolemy Semua argumen ini sama benarnya saat menggunakan auto. Itu sepele untuk melihat operasi apa yang xdidukung dari konteks. Bahkan, jenis memberi Anda tidak ada informasi tambahan: dalam kedua kasus Anda membutuhkan sekunder (IDE, dokumentasi, pengetahuan / memori) untuk memberitahu Anda set operasi yang didukung.
Konrad Rudolph
1
@Ptolemy Itu hanya berlaku jika Anda berada dalam situasi yang sangat berbelit-belit bahwa Anda tidak tahu apa beginhasil tetapi Anda tidak tahu apa std::vector<>::iteratoryang. Dan Anda perlu menggunakan alat pemrograman yang buruk yang tidak bisa memberi Anda informasi ini sepele. Ini sangat berbelit-belit. Pada kenyataannya, Anda tahu keduanya begindan iteratoratau tidak sama sekali, dan Anda harus menggunakan IDE atau editor yang dapat dengan mudah menyediakan informasi yang relevan bagi Anda. Setiap IDE dan editor pemrograman modern dapat melakukannya.
Konrad Rudolph
11

PRO

Kode Anda:

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

tidak akan dikompilasi, karena nama yang bergantung pada templat.

Ini adalah sintaks yang benar:

for( typename std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

Sekarang lihat berapa lama deklarasi jenisnya. Ini menjelaskan mengapa autokata kunci diperkenalkan. Ini:

for( auto it = x.begin(); it != x.end(); i++)

lebih ringkas. Jadi, ini adalah pro.


MENIPU

Anda harus sedikit berhati-hati. Dengan kata kunci auto, Anda mendapatkan tipe yang Anda nyatakan.

Sebagai contoh :

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto it : v )
{
  ++ it;   // ops modifying copies of vector's elements
}

vs.

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto & it : v )   // mind the reference
{
  ++ it;   // ok, vector's elements modified
}

Untuk menyimpulkan: ya, Anda harus melakukannya, tetapi tidak menggunakannya secara berlebihan. Beberapa orang cenderung menggunakannya terlalu banyak, dan menempatkan otomatis di mana-mana, seperti pada contoh berikut:

auto i = 0;

vs.

int i = 0;
BЈовић
sumber
auto i = 0. Bersalah. Saya melakukannya. Tapi itu karena saya tahu itu 0adalah tipe literal int. (dan konstanta oktal ;-))
Laurent LA RIZZA
6

Ya kamu harus! autotidak menghapus tipe; bahkan jika Anda "tidak tahu" apa x.begin()itu, kompiler tahu dan akan melaporkan kesalahan jika Anda mencoba menggunakan jenis itu secara salah. Juga, tidak biasa untuk ditiru mapdengan a vector<pair<Key,Value>>, sehingga penggunaan kode autoakan bekerja untuk kedua representasi kamus.

zvrba
sumber
4

Ya, Anda harus menggunakan autosebagai aturan default. Ini memiliki keuntungan mentah dibandingkan dengan menentukan jenis:

  • Itu tidak membuat Anda mengetik hal-hal yang sudah diketahui oleh kompiler.
  • Itu membuat jenis variabel "ikuti" setiap perubahan dalam jenis nilai kembali.
  • Melakukan hal itu, itu mencegah pengenalan diam-diam konversi implisit dan memotong inisialisasi variabel lokal.
  • Ini menghilangkan kebutuhan beberapa jenis perhitungan eksplisit dalam template.
  • Ini menghilangkan kebutuhan penamaan jenis kembali dengan nama panjang. (yang Anda salin-tempel dari diagnostik kompiler)

Di sinilah Anda punya pilihan. Ada juga kasus di mana Anda tidak punya pilihan:

  • Ini memungkinkan deklarasi variabel dari tipe unutterable, seperti tipe lambda.

Asalkan Anda tahu persis apa yang autodilakukan, itu tidak memiliki kerugian.

Laurent LA RIZZA
sumber