Apakah ada kerugian untuk mendeklarasikan variabel dengan otomatis di C ++?

143

Tampaknya itu autoadalah fitur yang cukup signifikan untuk ditambahkan dalam C ++ 11 yang tampaknya mengikuti banyak bahasa yang lebih baru. Seperti bahasa seperti Python, saya belum melihat adanya deklarasi variabel eksplisit (saya tidak yakin apakah mungkin menggunakan standar Python).

Apakah ada kelemahan menggunakan autountuk mendeklarasikan variabel daripada secara eksplisit mendeklarasikannya?

DxAlpha
sumber
1
Lihat juga: stackoverflow.com/questions/6434971/… , stackoverflow.com/questions/15254461/… , stackoverflow.com/questions/6900459/… , stackoverflow.com/questions/8430053/is-c11-auto-type-dangerous , dan mungkin yang lain. Tidak yakin apakah ini duplikat yang tepat, tetapi mereka pasti kandidat.
Cody Gray
3
Satu-satunya downside yang saya temukan adalah ketika saya harus mem-porting basis kode ke platform (konsol) yang kompilernya tidak mendukung (dan tidak berniat mendukung) fitur-fitur C ++ 11!
Sam
7
Hanya untuk kelengkapan GotW # 94 "Almost Always Auto": herbalutter.com/2013/08/12/…
Richard Critten
1
Saya sedang mendengarkan cppcast dan ada menyebutkan clash b / w auto dan daftar inisialisasi. Saya akan mencoba menemukan podcast itu.
Abhinav Gauniyal
2
Kelemahan pertama yang saya pikir berdampak pada keterbacaan kode
ggrr

Jawaban:

111

Anda hanya bertanya tentang kekurangannya, jadi saya menyoroti beberapa di antaranya. Bila digunakan dengan baik, automemiliki beberapa keunggulan juga. Kekurangannya adalah karena mudahnya penyalahgunaan, dan dari meningkatnya potensi kode untuk berperilaku dengan cara yang tidak disengaja.

Kelemahan utama adalah bahwa, dengan menggunakan auto, Anda tidak perlu tahu jenis objek yang dibuat. Ada juga kesempatan di mana programmer mungkin mengharapkan kompiler untuk menyimpulkan satu jenis, tetapi kompiler dengan tegas menyimpulkan yang lain.

Diberikan deklarasi seperti

auto result = CallSomeFunction(x,y,z);

Anda tidak perlu memiliki pengetahuan tentang jenis apa resultitu. Itu mungkin sebuah int. Mungkin sebuah pointer. Mungkin sesuatu yang lain. Semua itu mendukung operasi yang berbeda. Anda juga dapat secara dramatis mengubah kode dengan perubahan kecil seperti

auto result = CallSomeFunction(a,y,z);

karena, tergantung pada kelebihan apa yang ada untuk CallSomeFunction()jenis hasil mungkin sama sekali berbeda - dan karena itu kode selanjutnya mungkin berperilaku sangat berbeda dari yang dimaksudkan. Anda mungkin tiba-tiba memicu pesan kesalahan dalam kode selanjutnya (mis. Kemudian intmencoba untuk mengubah referensi , mencoba mengubah sesuatu yang sekarang const). Perubahan yang lebih menyeramkan adalah saat perubahan Anda melewati kompiler, tetapi kode selanjutnya berperilaku dengan cara yang berbeda dan tidak diketahui - mungkin buggy.

Karena itu, tidak memiliki pengetahuan eksplisit tentang jenis beberapa variabel membuatnya lebih sulit untuk membenarkan klaim bahwa kode berfungsi sebagaimana dimaksud. Ini berarti lebih banyak upaya untuk membenarkan klaim "cocok untuk tujuan" dalam domain kritis tinggi (mis. Keselamatan kritis atau misi kritis).

Kelemahan lainnya, yang lebih umum, adalah godaan bagi seorang programmer untuk digunakan autosebagai instrumen tumpul untuk memaksa kode dikompilasi, daripada memikirkan apa yang dilakukan kode, dan bekerja untuk memperbaikinya.

Peter
sumber
58
Sangat menarik untuk dicatat bahwa jika contoh-contoh tersebut adalah kelemahan dari penggunaan auto, maka sebagian besar bahasa yang diketik bebek mengalami kekurangan seperti itu oleh desain!
Leben Asa
11
Jika CallSomeFunction()mengembalikan jenis yang berbeda tergantung pada urutan argumennya, itu adalah cacat desain CallSomeFunction(), bukan masalah auto. Jika Anda tidak membaca dokumentasi fungsi yang Anda gunakan sebelum menggunakannya, itu adalah kesalahan programmer, bukan masalah auto. - Tapi saya mengerti bahwa Anda berperan sebagai penasihat setan di sini, hanya saja Nir Friedman memiliki kasus yang jauh lebih baik.
DevSolar
16
@DevSolar: Mengapa T CallSomeFunction(T, int, int)cacat desain? Jelas itu "mengembalikan jenis yang berbeda tergantung pada urutan argumennya."
MSalters
9
"Kelemahan utama adalah bahwa, dengan menggunakan auto, Anda tidak perlu tahu jenis objek yang sedang dibuat." Bisakah Anda menguraikan mengapa ini merupakan masalah auto, dan bukan masalah dengan temporer subekspresi? Mengapa itu auto result = foo();buruk, tetapi foo().bar()tidak?
Angew tidak lagi bangga dengan SO
24
Tampaknya dari komentar bahwa "kelemahan" sedang ditafsirkan sebagai alasan bahwa ada sesuatu yang tidak dapat diterima. Kelemahan dari fitur bahasa adalah kerugian yang perlu dipertimbangkan dan dibenarkan oleh pengembang untuk menerima atau tidak - yaitu membuat trade-off teknik. Saya tidak membuat selimut klaim tentang mengapa fitur harus atau tidak boleh digunakan.
Peter
76

Ini bukan kelemahan autodengan cara berprinsip persis, tetapi dalam hal praktis tampaknya menjadi masalah bagi sebagian orang. Pada dasarnya, beberapa orang entah: a) memperlakukan autosebagai penyelamat untuk jenis dan mematikan otak mereka saat menggunakannya, atau b) lupa bahwa autoselalu menyimpulkan jenis nilai. Ini menyebabkan orang melakukan hal-hal seperti ini:

auto x = my_obj.method_that_returns_reference();

Ups, kami baru saja menyalin beberapa objek. Seringkali bug atau kinerja gagal. Kemudian, Anda bisa mengayunkan ke arah lain juga:

const auto& stuff = *func_that_returns_unique_ptr();

Sekarang Anda mendapatkan referensi yang menggantung. Masalah-masalah ini tidak disebabkan oleh autosama sekali, jadi saya tidak menganggapnya sebagai argumen yang sah untuk menentangnya. Tapi sepertinya automembuat masalah ini lebih umum (dari pengalaman pribadi saya), untuk alasan yang saya sebutkan di awal.

Saya pikir ketika orang-orang akan menyesuaikan, dan memahami pembagian kerja: automenyimpulkan jenis yang mendasarinya, tetapi Anda masih ingin berpikir tentang referensi-ke-kekakuan dan kekekalan. Tapi itu butuh sedikit waktu.

Nir Friedman
sumber
Mengapa Anda bisa menyalin objek mahal?
Laurent LA RIZZA
3
@LaurentLARIZZA: Beberapa kelas memiliki copy constructor hanya karena kadang-kadang dibutuhkan (misalnya, instance std::vector). Menjadi mahal untuk menyalin bukan milik kelas, tetapi benda individu. Jadi method_that_returns_referencemungkin merujuk ke objek kelas yang memiliki copy constructor, tetapi objek mana yang cukup mahal untuk menyalin (dan tidak dapat dipindahkan dari).
Marc van Leeuwen
@MarcvanLeeuwen: Jika objek itu mahal untuk disalin, dan tidak bisa dipindahkan, mengapa benda itu disimpan dalam std::vector? (Karena itu mungkin, ya, atau karena Anda tidak mengontrol kelas, tapi bukan itu intinya) Jika mahal untuk menyalin, (dan tidak memiliki sumber daya, karena dapat disalin), mengapa tidak menggunakan SAP pada objek? Lokalitas data sudah terbunuh oleh ukuran objek.
Laurent LA RIZZA
2
@LaurentLARIZZA Bukan turunan dari sesuatu yang disimpan dalam vektor yang mahal, hanya vektor misal <double> yang mahal untuk disalin, ini adalah alokasi tumpukan + O (N) yang berfungsi. Bergerak adalah herring merah. Baris pertama yang saya tunjukkan akan menyalin, tidak bergerak, kecuali referensi yang dikembalikan adalah referensi nilai. SAP tidak ada di sini atau di sana. Faktanya adalah bahwa mahal untuk menyalin objek akan selalu ada.
Nir Friedman
4
@ Yakk Itu tidak bisa dengan aman melakukan itu, karena itu bisa mengiris. Satu-satunya hal aman yang bisa dilakukan adalah = deletekelebihan itu. Padahal yang lebih umum apa yang Anda katakan adalah solusi. Ini adalah topik yang telah saya jelajahi, jika Anda tertarik: nirfriedman.com/2016/01/18/… .
Nir Friedman
51

Jawaban lain menyebutkan kelemahan seperti "Anda tidak benar-benar tahu apa jenis variabelnya." Saya akan mengatakan bahwa ini sebagian besar terkait dengan konvensi penamaan ceroboh dalam kode. Jika antarmuka Anda diberi nama yang jelas, Anda tidak perlu peduli dengan tipe yang tepat. Tentu, auto result = callSomeFunction(a, b);tidak banyak bercerita. Tetapi auto valid = isValid(xmlFile, schema);memberitahu Anda cukup untuk digunakan validtanpa harus peduli apa jenis persisnya. Lagi pula, hanya dengan if (callSomeFunction(a, b)), Anda tidak akan tahu jenisnya juga. Sama dengan objek sementara subekspresi lainnya. Jadi saya tidak menganggap ini sebagai kelemahan nyata auto.

Saya akan mengatakan kelemahan utamanya adalah bahwa kadang-kadang, tipe pengembalian yang tepat bukanlah yang ingin Anda kerjakan. Akibatnya, kadang-kadang jenis pengembalian aktual berbeda dari jenis pengembalian "logis" sebagai detail implementasi / optimisasi. Template ekspresi adalah contoh utama. Katakanlah kita punya ini:

SomeType operator* (const Matrix &lhs, const Vector &rhs);

Secara logis, kita berharap SomeTypedemikian Vector, dan kita pasti ingin memperlakukannya seperti itu dalam kode kita. Namun, ada kemungkinan bahwa untuk tujuan optimasi, perpustakaan aljabar yang kami gunakan mengimplementasikan templat ekspresi, dan tipe pengembalian sebenarnya adalah ini:

MultExpression<Matrix, Vector> operator* (const Matrix &lhs, const Vector &rhs);

Sekarang, masalahnya adalah bahwa MultExpression<Matrix, Vector>kemungkinan besar akan menyimpan const Matrix&dan secara const Vector&internal; ia mengharapkan bahwa itu akan dikonversi ke Vectorsebelum akhir dari ekspresi penuhnya. Jika kita memiliki kode ini, semuanya baik-baik saja:

extern Matrix a, b, c;
extern Vector v;

void compute()
{
  Vector res = a * (b * (c * v));
  // do something with res
}

Namun, jika kami digunakan di autosini, kami bisa mendapat masalah:

void compute()
{
  auto res = a * (b * (c * v));
  // Oops! Now `res` is referring to temporaries (such as (c * v)) which no longer exist
}
Angew tidak lagi bangga dengan SO
sumber
3
@NirFriedman Anda benar itu kuat, tapi saya benar-benar merasa automemiliki sedikit kekurangan, jadi saya berdiri dengan kekuatan itu. Dan contoh lain dari proxy dll. Termasuk berbagai "pembangun string" dan objek serupa yang ditemukan di DSL.
Angew tidak lagi bangga dengan SO
2
Saya telah digigit oleh templat ekspresi dan autosebelumnya, khususnya dengan perpustakaan Eigen. Ini terutama rumit karena masalah sering tidak muncul dalam debug build.
Dan
1
Penggunaan autocan juga menggigit saat menggunakan perpustakaan matriks Armadillo , yang banyak menggunakan meta-pemrograman templat untuk keperluan optimasi. Untungnya para pengembang telah menambahkan fungsi .eval () yang dapat digunakan untuk menghindari masalah denganauto
mtall
2
"Jika antarmuka Anda diberi nama yang jelas, Anda tidak perlu peduli apa jenis pastinya" Kompiler Anda tidak dapat memeriksa kebenaran kode Anda dengan mempelajari nama-nama variabel. Ini adalah keseluruhan poin dari sistem tipe. Membabi buta melewati itu konyol!
Lightness Races in Orbit
1
@ Angew: Ini bukan masalah bagi temporaries karena Anda biasanya langsung menggunakannya, yang tanpa autobiasanya melibatkan semacam jenis pemeriksaan (dan memercik autodi mana-mana menghilangkan jenis keamanan seperti halnya di tempat lain). Itu bukan perbandingan yang bagus.
Lightness Races in Orbit
13

Salah satu kelemahan adalah bahwa kadang-kadang Anda tidak dapat mendeklarasikan const_iteratordengan auto. Anda akan mendapatkan iterator biasa (bukan const) dalam contoh kode yang diambil dari pertanyaan ini :

map<string,int> usa;
//...init usa
auto city_it = usa.find("New York");
ks1322
sumber
3
Nah, Anda mendapatkan iteratordalam hal apapun karena peta Anda bukan const. jika Anda ingin mengubahnya menjadi const_iterator, tentukan jenis variabel secara eksplisit seperti biasa, atau ekstrak metode sehingga peta Anda adalah konst dalam konteks Anda find. (Saya lebih suka yang terakhir. SRP.)
Laurent LA RIZZA
auto city_it = static_cast<const auto&>(map).find("New York")? atau, dengan C ++ 17 auto city_if = std::as_const(map).find("New York"),.
Dev Null
11

Itu membuat kode Anda sedikit lebih sulit, atau membosankan, untuk dibaca. Bayangkan sesuatu seperti itu:

auto output = doSomethingWithData(variables);

Sekarang, untuk mengetahui tipe output, Anda harus melacak tanda tangan doSomethingWithDatafungsi.

Skam
sumber
40
Tidak selalu. auto it = vec.begin();jauh lebih mudah dibaca daripada std::vector<std::wstring>::iterator it = vec.begin();misalnya.
Jonathan Potter
4
Sepakat. Itu tergantung pada use case. Saya bisa lebih tepat tentang itu.
Skam
1
@Lihat, ya, orang yang menggunakan otomatis seperti itu melakukan kesalahan.
lciamp
6
"Lacak tanda tangan fungsi", jika itu bukan mouse yang melayang-layang atau penekanan tombol saja ("ikuti simbol" / "buka deklarasi" / apa pun namanya), Anda perlu mengkonfigurasi editor Anda lebih banyak atau beralihlah ke IDE yang dapat melakukan ini tanpa konfigurasi ... Namun, poin Anda masih valid.
hyde
6
Saya perhatikan bahwa tidak dalam IDE tetapi di lubang kecil diffs ketika meninjau checkin! Dengan otomatis mereka lebih sulit dibaca karena alasan itu.
JDługosz
10

Seperti pengembang ini , saya benci auto. Atau lebih tepatnya, aku benci bagaimana orang menyalahgunakan auto.

Saya berpendapat (kuat) autountuk membantu Anda menulis kode generik, bukan untuk mengurangi mengetik .
C ++ adalah bahasa yang tujuannya membiarkan Anda menulis kode yang kuat, bukan untuk meminimalkan waktu pengembangan.
Ini cukup jelas dari banyak fitur C ++, tapi sayangnya beberapa yang lebih baru seperti autoitu mengurangi mengetik orang yang menyesatkan sehingga berpikir mereka harus mulai malas mengetik.

Pada automasa pra- hari, orang menggunakan typedefs, yang sangat bagus karena typedef memungkinkan perancang perpustakaan untuk membantu Anda mengetahui apa yang seharusnya menjadi tipe pengembalian, sehingga perpustakaan mereka berfungsi seperti yang diharapkan. Saat Anda menggunakan auto, Anda mengambil kontrol itu dari desainer kelas dan alih-alih meminta kompiler untuk mencari tahu apa yang harus menjadi tipe, yang menghapus salah satu alat C ++ paling kuat dari kotak alat dan berisiko melanggar kode mereka.

Secara umum, jika Anda menggunakan auto, itu harus karena kode Anda berfungsi untuk semua jenis yang masuk akal , bukan karena Anda terlalu malas untuk menuliskan jenis yang harusnya bekerja. Jika Anda menggunakan autosebagai alat untuk membantu kemalasan, maka yang terjadi adalah Anda akhirnya mulai memperkenalkan bug halus di program Anda, biasanya disebabkan oleh konversi tersirat yang tidak terjadi karena Anda menggunakannya auto.

Sayangnya, bug ini sulit untuk diilustrasikan dalam contoh singkat di sini karena singkatnya mereka membuat mereka kurang meyakinkan daripada contoh aktual yang muncul dalam proyek pengguna - namun, mereka muncul dengan mudah dalam kode template-berat yang mengharapkan konversi implisit tertentu untuk mengambil tempat.

Jika Anda ingin contoh, ada satu di sini . Namun, sedikit catatan: sebelum tergoda untuk melompat dan mengkritik kode: perlu diingat bahwa banyak perpustakaan terkenal dan dewasa telah dikembangkan di sekitar konversi implisit, dan mereka ada di sana karena mereka memecahkan masalah yang bisa sulit jika bukan tidak mungkin untuk memecahkan sebaliknya. Cobalah mencari solusi yang lebih baik sebelum mengkritik mereka.

pengguna541686
sumber
3
which was great because typedef allowed the designer of the library to help you figure out what the return type should be, so that their library works as expected. When you use auto, you take away that control from the class's designer and instead ask the compiler to figure out what the type should beIMO bukan alasan yang bagus. IDE terkini, Visual Studio 2015 misalnya, memungkinkan Anda untuk memeriksa jenis variabel dengan mengarahkan kursor auto. Ini * persis * sama dengan yang typedefada.
Sombrero Chicken
@JameyD: Anda kehilangan beberapa poin penting di sana: (1) Argumen IDE Anda hanya berfungsi jika tipenya konkret, bukan templated. IDE tidak dapat memberi tahu Anda tipe yang benar untuk tipe dependen, mis typename std::iterator_traits<It>::value_type. (2) Intinya adalah bahwa jenis yang disimpulkan tidak harus "persis sama" dengan jenis yang benar yang dimaksudkan oleh perancang kode sebelumnya; dengan menggunakan auto, Anda menghilangkan kemampuan desainer untuk menentukan jenis yang benar.
user541686
Anda pada dasarnya berbicara tentang proksi, yang salah satu jawabannya sudah disebutkan. Template ekspresi dan omong kosong <bool> vektor bukan kode sehari-hari bagi kebanyakan orang. Dalam sebagian besar situasi, Anda tidak ingin konversi tersirat, dan otomatis membantu dengan itu. Herb Sutter berbicara tentang kelebihan auto secara luas di salah satu posting blognya, dan ini bukan tentang penekanan tombol, dan juga bukan hanya untuk kode generik. Juga, tautan pertama yang Anda berikan, posting blog hanyalah saran yang mengerikan (itulah sebabnya ia dikritik dengan giat di bagian komentarnya).
Nir Friedman
@NirFriedman: "... vector<bool>omong kosong" ... maaf? Bagaimana menurut Anda bitsetdiimplementasikan? Atau apakah Anda menganggap wadah bit sebagai omong kosong sama sekali ?!
user541686
1
@NirFriedman: Tidak ada yang tentang vektor <bool> adalah berita baru bagi saya. Apa yang saya coba katakan kepada Anda dan bahwa Anda secara terang-terangan menolak untuk memahami adalah bahwa untuk keperluan pertanyaan ini, bitet tidak berbeda dengan vektor <bool> - keduanya menggunakan proxy, karena proxy itu dianggap berguna , dan fakta bahwa proksi berguna adalah kenyataan yang harus Anda terima alih-alih hidup dalam penyangkalan. Bisakah Anda berhenti mengubah ini menjadi perdebatan tentang apakah menurut Anda proksi bermanfaat? Itu bukan topik perdebatan, dan juga, pendapat Anda tentang mereka hanyalah pendapat Anda, bukan semacam fakta.
user541686
6

autotidak memiliki kelemahan per se , dan saya menganjurkan untuk (goyah) menggunakannya di mana-mana dalam kode baru. Ini memungkinkan kode Anda untuk secara konsisten mengetik-cek, dan secara konsisten menghindari pemotongan diam. (Jika Bberasal dari Adan fungsi yang kembali Atiba-tiba kembali B, maka autoberperilaku seperti yang diharapkan untuk menyimpan nilai pengembaliannya)

Meskipun, kode lama pre-C ++ 11 dapat mengandalkan konversi implisit yang disebabkan oleh penggunaan variabel yang diketik secara eksplisit. Mengubah variabel yang diketik secara eksplisit untuk autodapat mengubah perilaku kode , jadi sebaiknya Anda berhati-hati.

Laurent LA RIZZA
sumber
Downvoting itu adil, tetapi bisakah Anda mengomentari mengapa?
Laurent LA RIZZA
Saya tidak menurunkan suara Anda, tetapi automemiliki kekurangan per se (atau setidaknya - banyak yang berpikir demikian). Pertimbangkan contoh yang diberikan dalam pertanyaan kedua dalam diskusi panel ini dengan Sutter, Alexandrescu dan Meyers: Jika Anda memiliki auto x = foo(); if (x) { bar(); } else { baz(); }dan foo()kembali bool- apa yang terjadi jika foo()perubahan untuk mengembalikan enum (tiga opsi, bukan dua)? The autokode akan terus bekerja, tapi menghasilkan hasil yang tidak diharapkan.
einpoklum
@einpoklum: Dan apakah menggunakan boolalih-alih automengubah apa pun jika ada enum yang tidak dicopot? Saya mungkin salah (tidak dapat memeriksa di sini), tetapi saya pikir satu-satunya perbedaan adalah bahwa konversi boolterjadi pada deklarasi variabel dan bukan pada evaluasi kondisi dalam if. Jika enumscoped, maka konversi ke booltidak akan terjadi tanpa pemberitahuan eksplisit.
Laurent LA RIZZA
4

Kata kunci autocukup menyimpulkan jenis dari nilai pengembalian. Oleh karena itu, ini tidak setara dengan objek Python, mis

# Python
a
a = 10       # OK
a = "10"     # OK
a = ClassA() # OK

// C++
auto a;      // Unable to deduce variable a
auto a = 10; // OK
a = "10";    // Value of const char* can't be assigned to int
a = ClassA{} // Value of ClassA can't be assigned to int
a = 10.0;    // OK, implicit casting warning

Karena autodideduksi selama kompilasi, itu tidak akan memiliki kekurangan saat runtime sama sekali.

Leben Asa
sumber
1
ya, itu pada dasarnya melakukan apa yang dilakukan type()dengan python. Itu menyimpulkan jenis, itu tidak membuat variabel baru dari jenis itu.
lciamp
2
@ lciamp Sebenarnya, itu mungkin decltype. autokhusus untuk penugasan variabel.
Cubic
4

Apa yang tidak disebutkan di sini sejauh ini, tetapi untuk dirinya sendiri bernilai jawaban jika Anda bertanya kepada saya.

Karena (walaupun semua orang harus sadar bahwa C != C++) kode yang ditulis dalam C dapat dengan mudah dirancang untuk menyediakan basis untuk kode C ++ dan karenanya dirancang tanpa terlalu banyak upaya untuk menjadi kompatibel dengan C ++, ini bisa menjadi persyaratan untuk desain.

Saya tahu tentang beberapa aturan di mana beberapa konstruksi yang didefinisikan dengan baik Ctidak valid untuk C++dan sebaliknya. Tapi ini hanya akan menghasilkan executable yang rusak dan klausa UB yang berlaku berlaku yang paling sering diperhatikan oleh perulangan aneh yang mengakibatkan crash atau apa pun (atau bahkan mungkin tetap tidak terdeteksi, tetapi itu tidak masalah di sini).

Tapi autoapakah pertama kali 1 ini berubah!

Bayangkan Anda digunakan autosebagai specifier kelas penyimpanan sebelum dan mentransfer kode. Bahkan tidak perlu (tergantung pada cara itu digunakan) "istirahat"; itu sebenarnya bisa mengubah perilaku program secara diam-diam.

Itu sesuatu yang harus diingat.


1 Setidaknya pertama kali aku sadar.

dhein
sumber
1
Anda tetap akan mendapatkan kesalahan kompiler saat mencoba mengkompilasi.
Sombrero Chicken
@JameyD: Apa yang akan melakukannya? mengapa 2 situasi kode yang valid dengan makna berbeda harus selalu bermasalah?
dhein
8
Jika Anda mengandalkan "tanpa tipe menyiratkan int" di C, Anda layak mendapatkan semua hal buruk yang akan Anda dapatkan dari ini. Dan jika Anda tidak mengandalkan itu, menggunakan autosebagai specifier kelas penyimpanan bersama tipe akan memberi Anda kesalahan kompilasi yang bagus di C ++ (yang merupakan Good Thing dalam kasus ini).
Angew tidak lagi bangga dengan SO
1
@ Baru baiklah itu kasus yang saya maksudkan, ya. Saya tidak melakukan ini. Tapi itu adalah sesuatu yang setidaknya harus diingat.
dhein
3

Salah satu alasan yang dapat saya pikirkan adalah bahwa Anda kehilangan kesempatan untuk memaksa kelas yang dikembalikan. Jika fungsi atau metode Anda mengembalikan panjang 64 bit, dan Anda hanya menginginkan 32 unsigned int, maka Anda kehilangan kesempatan untuk mengontrolnya.

kblansit
sumber
1
Ada static_cast, dan IIRC misalnya Meyers 'Effective Modern C ++ bahkan merekomendasikan menggunakannya untuk menentukan tipe untuk variabel yang diketik secara otomatis.
hyde
2

Seperti yang saya jelaskan dalam jawaban auto ini kadang-kadang dapat menghasilkan situasi funky yang tidak Anda inginkan. Anda harus secara eksplisit mengatakan auto&memiliki tipe referensi saat melakukan saja autodapat membuat tipe pointer. Ini dapat menyebabkan kebingungan dengan menghilangkan specifier secara bersamaan, menghasilkan salinan referensi alih-alih referensi yang sebenarnya.

Sombrero Chicken
sumber
2
Itu tidak funky. Itulah yang autoterjadi, jangan pernah menyimpulkan referensi atau consttipe. Untuk autoreferensi, sebaiknya Anda gunakan auto&&. (referensi universal) Jika jenisnya tidak murah untuk disalin atau memiliki sumber daya, maka jenis tersebut seharusnya tidak dapat disalin untuk memulai.
Laurent LA RIZZA
1

Contoh menjengkelkan lainnya:

for (auto i = 0; i < s.size(); ++i)

menghasilkan peringatan ( comparison between signed and unsigned integer expressions [-Wsign-compare]), karena iint yang ditandatangani. Untuk menghindari ini, Anda perlu menulis misalnya

for (auto i = 0U; i < s.size(); ++i)

atau mungkin lebih baik:

for (auto i = 0ULL; i < s.size(); ++i)
Paul R
sumber
1
Ya saya menemukan ini menjengkelkan juga. Tetapi lubang dalam bahasa itu ada di tempat lain. Agar kode ini benar-benar portabel, dengan asumsi sizepengembalian size_t, Anda harus dapat memiliki huruf size_tliteral 0z. Tetapi Anda dapat mendeklarasikan UDL untuk melakukan ini. ( size_t operator""_z(...))
Laurent LA RIZZA
1
Keberatan teoretis murni: unsignedsangat mungkin tidak akan cukup besar untuk menampung semua nilai std::size_tpada arsitektur arus utama, sehingga jika seseorang memiliki wadah dengan jumlah elemen yang sangat besar, penggunaan unsigneddapat menyebabkan loop tak terbatas pada rentang yang lebih rendah. indeks. Meskipun ini tidak mungkin menjadi masalah, std::size_tharus digunakan untuk mendapatkan kode bersih yang maksud sinyal dengan benar. Saya tidak yakin bahkan unsigned long longdijamin cukup, walaupun dalam praktiknya mungkin harus sama.
underscore_d
@underscore_d: ya, titik adil - unsigned long longdijamin setidaknya 64 bit, tetapi secara teori size_tbisa lebih besar dari ini, saya kira. Tentu saja jika Anda memiliki> 2 ^ 64 elemen dalam wadah Anda, maka Anda mungkin memiliki masalah yang lebih besar untuk dikhawatirkan ... ;-)
Paul R
1

Saya pikir autobagus ketika digunakan dalam konteks lokal, di mana pembaca dengan mudah & jelas dapat mengurangi jenisnya, atau didokumentasikan dengan baik dengan komentar dari jenisnya atau nama yang menyimpulkan jenis yang sebenarnya. Mereka yang tidak mengerti cara kerjanya mungkin mengambilnya dengan cara yang salah, seperti menggunakannya sebagai gantinya templateatau serupa. Berikut adalah beberapa kasus penggunaan yang baik dan buruk menurut saya.

void test (const int & a)
{
    // b is not const
    // b is not a reference

    auto b = a;

    // b type is decided by the compiler based on value of a
    // a is int
}

Penggunaan yang baik

Iterator

std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int> v();

..

std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int>::iterator it = v.begin();

// VS

auto vi = v.begin();

Pointer fungsi

int test (ClassWithLongName1 a, ClassWithLongName2 b, int c)
{
    ..
}

..

int (*fp)(ClassWithLongName1, ClassWithLongName2, int) = test;

// VS

auto *f = test;

Penggunaan yang buruk

Aliran data

auto input = "";

..

auto output = test(input);

Fungsi Tanda Tangan

auto test (auto a, auto b, auto c)
{
    ..
}

Kasus-kasus sepele

for(auto i = 0; i < 100; i++)
{
    ..
}
Khaled.K
sumber
Saat Anda menginginkan int, Anda harus mengetikkan satu lagi arang jika mau auto. Itu tidak bisa diterima
Rerito
@Rerito ya, ini intmudah dilihat di sini & mengetik intlebih pendek. Itu sebabnya ini adalah kasus sepele.
Khaled.K
0

Saya terkejut tidak ada yang menyebutkan ini, tetapi anggap Anda menghitung faktorial dari sesuatu:

#include <iostream>
using namespace std;

int main() {
    auto n = 40;
    auto factorial = 1;

    for(int i = 1; i <=n; ++i)
    {
        factorial *= i;
    }

    cout << "Factorial of " << n << " = " << factorial <<endl;   
    cout << "Size of factorial: " << sizeof(factorial) << endl; 
    return 0;
}

Kode ini akan menampilkan ini:

Factorial of 40 = 0
Size of factorial: 4

Itu jelas bukan hasil yang diharapkan. Itu terjadi karena automenyimpulkan jenis faktorial variabel intkarena ditugaskan 1.

xilpex
sumber