Itu membuatnya lebih mudah dibaca, ditambah, jika Anda pernah berubah i++menjadi i+=2(misalnya), itu akan berjalan untuk waktu yang sangat lama (atau mungkin selamanya). Sekarang, karena Anda biasanya menggunakan <untuk kasus-kasus di mana Anda meningkatkan iterator lebih dari 1, Anda mungkin juga menggunakan <untuk kasus di mana Anda menambahnya dengan 1 (untuk konsistensi).
barak manos
112
5 != iitu jahat
Slava
27
Anda harus selalu sadar akan apa yang Anda lakukan, tetapi Anda tetap akan membuat kesalahan. Menggunakan <mengurangi kemungkinan seseorang memperkenalkan bug ke dalam kode ini.
Aurast
40
@OleTange Jika Anda melakukan iterasi menggunakan angka floating point Anda sudah kacau ..
CaptainCodeman
29
@Slava ... tidak jahat. Anda tampaknya belum pernah menggigit C oleh kesalahan ketik sederhana yang membuat perbedaan antara if ( i == 5 ) ...dan if ( i = 5 ). Hal yang sangat berbeda. Membalik operan mencegah masalah: karena literal tidak lvals, mereka tidak dapat ditugaskan dan kompiler melemparkan pada kesalahan ketik. @Zingam: pemrograman defensif yang bagus!
Nicholas Carey
Jawaban:
303
while(time !=6:30pm){Work();}
Sekarang jam 6:31 sore ... Sial, sekarang kesempatan berikutnya untuk pulang adalah besok! :)
Ini untuk menunjukkan bahwa pembatasan yang lebih kuat memitigasi risiko dan mungkin lebih intuitif untuk dipahami.
Terkadang, mencoba untuk "mengurangi risiko" akhirnya menyembunyikan bug. Jika desain loop harus mencegah 6:30 dari tergelincir oleh tanpa disadari, maka menggunakan <akan menyembunyikan bug tetapi menggunakan !=akan membuat jelas bahwa ada masalah.
Adrian McCarthy
27
@AdrianMcCarthy: Belum tentu; itu hanya bisa memperkenalkan bug kedua, membuat diagnosis lebih sulit .
Lightness Races in Orbit
4
@AdrianMcCarthy: Itu maksud saya; Anda bisa memiliki beberapa contohnya yang belum Anda lihat;)
Lightness Races in Orbit
6
Iterator adalah contoh sempurna dari titik @AdrianMcCarthy. Perbandingan yang disarankan untuk mereka adalah! = Bukannya <.
Taekahn
5
Saya telah melihat persis kesalahan ini (dan itu menyebabkan debugging 3 bulan) - tetapi jawaban ini sepenuhnya melenceng. Dalam contoh yang diberikan itu tidak mungkin untuk kondisi akhir untuk dilewatkan. Anda bahkan bisa mengatakan bahwa untuk secara sadar memilih! = Lebih dari <adalah membuat pernyataan yang kuat tentang fakta ini. Mengurangi risiko yang secara definitif tidak ada adalah bau kode bagi saya. (Karena itu, Anda dapat juga berpendapat bahwa <adalah idiomatik, bahwa itu adalah alasan yang baik untuk menggunakannya seperti apa pun.)
Ian Goldby
95
Tidak ada alasan teknis. Tetapi ada mitigasi risiko, rawatan dan pemahaman kode yang lebih baik.
<atau >pembatasan yang lebih kuat daripada !=dan memenuhi tujuan yang sama persis dalam banyak kasus (saya bahkan akan mengatakan dalam semua kasus praktis).
Ada pertanyaan rangkap di sini ; dan satu jawaban yang menarik .
Ada beberapa jenis, seperti iterator, yang tidak mendukung <atau>, tetapi mendukung == dan! =.
Simon B
1
Ini untuk loop dengan int . Tidak ada iterator.
Ely
7
"Tapi ada mitigasi risiko, rawatan dan pemahaman kode yang lebih baik." Semua itu, dengan tepat, merupakan alasan teknis. :-)
TJ Crowder
@TJCrowder Apa jenis alasannya ketika Anda hanya ingin berbicara tentang apa yang akan dilakukan mesin sebagai hasilnya?
Brilliand
1
@DanSheppard Saya biasanya akan mempertimbangkan mitigasi risiko dan pemeliharaan untuk menjadi alasan bisnis, dan pemahaman kode yang lebih baik menjadi alasan sosial (meskipun semua alasan itu diterapkan pada masalah teknis dalam kasus ini). Pertimbangan "Mitigasi risiko" sama sekali tidak terbatas pada masalah teknis, dan pertimbangan "pemahaman kode yang lebih baik" dapat berubah jika Anda menemukan diri Anda bekerja dengan kelompok orang yang berbeda (bahkan jika mesin yang terlibat tidak berubah sama sekali. ).
Brilliand
85
Ya ada alasannya. Jika Anda menulis (berbasis indeks lama polos) untuk loop seperti ini
for(int i = a; i < b;++i){}
maka itu berfungsi seperti yang diharapkan untuk nilai apa pun dari adan b(yaitu nol iterasi ketika a > bbukannya tak terbatas jika Anda telah menggunakan i == b;).
Di sisi lain, untuk iterator Anda akan menulis
for(auto it =begin; it !=end;++it)
karena setiap iterator harus mengimplementasikan suatu operator!=, tetapi tidak untuk setiap iterator dimungkinkan untuk menyediakan operator<.
Juga berbasis rentang untuk loop
for(auto e : v)
bukan hanya gula mewah, tetapi mereka secara terukur mengurangi peluang untuk menulis kode yang salah.
Contoh yang bagus. Saya akan tertarik pada kasus untuk !=bukannya <. Saya pribadi tidak pernah menggunakan yang saya pikir.
Ely
@ Elyasin Saya tidak menemukan yang baik, dan saya tidak ingin memposting yang buruk: Bayangkan Anda memiliki semacam wadah bundar, di mana Anda menambah + x modulo ukuran wadah N dan Anda ingin menghentikan lingkaran ketika Anda mencapai indeks tertentu .... well itu contoh yang sangat buruk. Mungkin saya akan menemukan yang lebih baik
idclev 463035818
Lingkaran yang sama dengan! = Bukannya <memperjelas apa keuntungan <(atau>) dalam konteks ini. for (int i=a; i != b; i++) {}
Paul Smith
10
Menggunakan apa pun selain !=dengan iterator cukup berbahaya, karena kadang - kadang iterator dapat lebih sedikit dibandingkan (misalnya pointer) tetapi perbandingannya tidak ada artinya (ini adalah daftar tertaut).
Zan Lynx
1
Belajarlah untuk menggunakan ruang putih, dengan serius.
Miles Rout
70
Anda dapat memiliki sesuatu seperti
for(int i =0; i<5;++i){...if(...) i++;...}
Jika variabel loop Anda ditulis oleh kode bagian dalam, variabel tersebut i!=5mungkin tidak memecah loop tersebut. Ini lebih aman untuk memeriksa ketimpangan.
Edit tentang keterbacaan. Bentuk ketimpangan jauh lebih sering digunakan. Oleh karena itu, ini sangat cepat dibaca karena tidak ada yang istimewa untuk dipahami (beban otak berkurang karena tugasnya sama). Jadi keren bagi pembaca untuk memanfaatkan kebiasaan ini.
Jenis batin "jika (kondisi) maka saya ++" adalah hal pertama yang saya pikirkan.
WernerCD
3
Datang dalam mengharapkan ini menjadi jawaban pilihan tertinggi; Saya terkejut bahwa saya harus menggulir sejauh ini untuk menemukannya. Ini lebih banyak meyakinkan meyakinkan programmer pemula daripada "well, Anda harus menggunakan kondisi terkuat". Jawaban lain, jika mereka tetap di atas, harus memasukkan ini sebagai penjelasan yang jelas dan jelas tentang apa yang bisa salah dengan kode yang diusulkan OP.
msouth
1
@msouth Saya sepenuhnya setuju, tetapi POV saya cukup subyektif;)
johan d
3
@msouth Saya suka ketika perilaku produksi yang tidak terduga mengekspos bug saya, bukan? :-)
deworde
3
@ Mulut Dengar, yang harus kita lakukan adalah jangan pernah melakukan kesalahan dan semuanya akan baik-baik saja Sederhana.
deworde
48
Dan last but not least, ini disebut pemrograman defensif , yang berarti untuk selalu mengambil kasus terkuat untuk menghindari kesalahan saat ini dan masa depan yang mempengaruhi program.
Satu-satunya kasus di mana pemrograman defensif tidak diperlukan adalah di mana negara telah dibuktikan oleh pra dan pasca-kondisi (tapi kemudian, membuktikan ini adalah yang paling defensif dari semua pemrograman).
Satu contoh yang baik untuk mendukung ini: Memori rentan terhadap bit flips ( SEUs ) yang disebabkan oleh radiasi. Ketika menggunakan suatu intuntuk suatu i != 15kondisi, penghitung akan berjalan untuk waktu yang lama jika ada sesuatu di atas bit keempat dibalik, terutama pada mesin sizeof(int)yang 64. , atau dalam superkomputer besar (karena begitu banyak memori yang ada).
Josh Sanford
2
Berpikir bahwa program Anda akan berjalan baik ketika radiasi mengubah ingatan Anda adalah cara yang optimis dan cara berpikir anti-bencana ... komentar yang bagus! :)
Luis Colorado
37
Saya berpendapat bahwa ungkapan itu seperti
for(int i =0; i <100;++i ){...}
lebih ekspresif dari niat daripada apa adanya
for(int i =0; i !=100;++i ){...}
Yang pertama dengan jelas menyatakan bahwa kondisi tersebut merupakan ujian untuk batas atas eksklusif pada rentang; yang terakhir adalah tes biner dari kondisi keluar. Dan jika badan loop adalah non-sepele, mungkin tidak jelas bahwa indeks hanya dimodifikasi dalam forpernyataan itu sendiri.
"Saya ingin loop ini berjalan paling banyak 5 kali" vs. "Saya ingin menjalankan loop ini sebanyak yang diperlukan, kecuali tepat 5 kali, yang saya tidak inginkan."
Uskup
+1 untuk menyebutkan batas atas pada rentang. Saya pikir ini penting untuk rentang numerik. ! = tidak mendefinisikan rentang yang tepat dalam for for loop seperti ini
element11
22
Iterator adalah kasus penting ketika Anda paling sering menggunakan !=notasi:
for(auto it = vector.begin(); it != vector.end();++it){// do stuff}
Memang: dalam praktiknya saya akan menulis hal yang sama dengan mengandalkan range-for:
for(auto& item : vector){// do stuff}
tetapi intinya tetap: orang biasanya membandingkan iterator menggunakan ==atau !=.
Iterator seringkali hanya memiliki gagasan tentang persamaan / ketidaksetaraan dan bukan urutan, itulah mengapa Anda menggunakannya !=untuk mereka. Misalnya, dalam std::vectorAnda dapat menggunakan <sebagai iterator terikat ke indeks / pointer, tetapi dalam std::settidak ada urutan yang ketat, karena berjalan pohon biner.
Martin C.
19
Kondisi loop adalah invarian loop yang dipaksakan.
Misalkan Anda tidak melihat isi loop:
for(int i =0; i !=5;++i){// ?}
dalam hal ini, Anda tahu pada awal iterasi loop yang itidak sama 5.
for(int i =0; i <5;++i){// ?}
dalam hal ini, Anda tahu pada awal iterasi loop yang ikurang dari5 .
Yang kedua jauh, jauh lebih banyak informasi daripada yang pertama, bukan? Sekarang, maksud programmer adalah (hampir pasti) sama, tetapi jika Anda mencari bug, memiliki kepercayaan diri dari membaca baris kode adalah hal yang baik. Dan yang kedua menegakkan invarian itu, yang berarti beberapa bug yang akan menggigit Anda dalam kasus pertama tidak dapat terjadi (atau tidak menyebabkan kerusakan memori, katakanlah) dalam kasus kedua.
Anda tahu lebih banyak tentang keadaan program, dari membaca lebih sedikit kode, <daripada dengan!= . Dan pada CPU modern, mereka mengambil jumlah waktu yang sama karena tidak ada perbedaan.
Jika Anda itidak dimanipulasi dalam tubuh loop, dan itu selalu meningkat sebesar 1, dan itu mulai kurang dari5 , tidak akan ada perbedaan. Tetapi untuk mengetahui apakah itu dimanipulasi, Anda harus mengkonfirmasi masing-masing fakta ini.
Beberapa fakta ini relatif mudah, tetapi Anda bisa salah. Namun, memeriksa seluruh tubuh loop itu menyebalkan.
Di C ++ Anda bisa menulis indexestipe seperti itu:
for(constint i : indexes(0,5)){// ?}
melakukan hal yang sama seperti salah satu dari dua forloop di atas , bahkan ke kompiler mengoptimalkannya ke kode yang sama. Di sini, bagaimanapun, Anda tahu bahwa itidak dapat dimanipulasi dalam tubuh loop, seperti yang dinyatakan const, tanpa kode merusak memori.
Semakin banyak informasi yang Anda dapatkan dari satu baris kode tanpa harus memahami konteksnya, semakin mudah melacak apa yang salah. <dalam hal bilangan bulat loop memberi Anda lebih banyak informasi tentang keadaan kode di baris itu daripada yang !=dilakukan.
Ini mungkin terjadi bahwa variabel idiatur ke beberapa nilai besar dan jika Anda hanya menggunakan !=operator Anda akan berakhir dalam loop tanpa akhir.
Tidak benar-benar tak ada habisnya - pada sebagian besar implementasi C, idiam-diam akan membungkus ketika maksimal. Tapi ya, kemungkinan besar lebih lama dari yang Anda siap tunggu.
usr2564301
12
Seperti yang dapat Anda lihat dari banyak jawaban lainnya, ada alasan untuk menggunakan <daripada! = Yang akan membantu dalam kasus tepi, kondisi awal, modifikasi penghitung putaran yang tidak diinginkan, dll ...
Jujur saja, saya tidak berpikir Anda bisa menekankan pentingnya konvensi. Untuk contoh ini akan cukup mudah bagi programmer lain untuk melihat apa yang Anda coba lakukan, tetapi itu akan menyebabkan pengambilan ganda. Salah satu pekerjaan saat pemrograman membuatnya menjadi dapat dibaca dan akrab bagi semua orang mungkin, jadi pasti ketika seseorang harus memperbarui / mengubah kode Anda, tidak perlu banyak usaha untuk mencari tahu apa yang Anda lakukan dalam blok kode yang berbeda . Jika saya melihat seseorang menggunakan !=, saya akan berasumsi ada alasan mereka menggunakannya bukan <dan jika itu adalah loop besar saya akan melihat seluruh hal mencoba untuk mencari tahu apa yang Anda lakukan yang membuat itu perlu ... dan itu membuang-buang waktu.
Seperti yang sudah dikatakan oleh Ian Newson, Anda tidak bisa dengan andal mengulang variabel mengambang dan keluar bersama !=. Misalnya,
for(double x=0; x!=1; x+=0.1){}
benar-benar akan berulang selamanya, karena 0,1 tidak dapat secara tepat diwakili dalam floating point, maka penghitungnya akan meleset 1. With < itu berakhir.
(Namun perlu dicatat bahwa pada dasarnya itu adalah perilaku yang tidak ditentukan apakah Anda mendapatkan 0,9999 ... sebagai nomor yang diterima terakhir - jenis pelanggaran yang kurang dari asumsi - atau sudah keluar di 1,0000000000000001000).
Saya mengambil kata sifat "teknis" berarti perilaku bahasa / keanehan dan efek samping kompiler seperti kinerja kode yang dihasilkan.
Untuk tujuan ini, jawabannya adalah: tidak (*). (*) Adalah "silakan baca manual prosesor Anda". Jika Anda bekerja dengan sistem RISC atau FPGA case-edge, Anda mungkin perlu memeriksa instruksi apa yang dihasilkan dan berapa biayanya. Tapi jika Anda menggunakan hampir semua arsitektur modern konvensional, maka tidak ada perbedaan tingkat prosesor yang signifikan dalam biaya antara lt, eq, nedan gt.
Jika Anda menggunakan kasus tepi Anda bisa menemukan bahwa !=memerlukan tiga operasi ( cmp, not, beq) vs dua ( cmp,blt xtr myo ). Sekali lagi, RTM dalam hal itu.
Sebagian besar, alasannya defensif / pengerasan, terutama ketika bekerja dengan pointer atau loop kompleks. Mempertimbangkan
Contoh yang kurang dibuat-buat adalah di mana Anda menggunakan nilai balik untuk melakukan peningkatan, menerima data dari pengguna:
#include<iostream>int main(){size_t len =5, step;for(size_t i =0; i != len;){
std::cout <<"i = "<< i <<", step? "<< std::flush;
std::cin >> step;
i += step;// here for emphasis, it could go in the for(;;)}}
Coba ini dan masukkan nilai 1, 2, 10, 999.
Anda dapat mencegah ini:
#include<iostream>int main(){size_t len =5, step;for(size_t i =0; i != len;){
std::cout <<"i = "<< i <<", step? "<< std::flush;
std::cin >> step;if(step + i > len)
std::cout <<"too much.\n";else
i += step;}}
Tapi yang mungkin Anda inginkan adalah
#include<iostream>int main(){size_t len =5, step;for(size_t i =0; i < len;){
std::cout <<"i = "<< i <<", step? "<< std::flush;
std::cin >> step;
i += step;}}
Ada juga sesuatu yang bias konvensi terhadap <, karena pemesanan dalam wadah standar sering bergantung operator<, misalnya hashing dalam beberapa wadah STL menentukan kesetaraan dengan mengatakan
Untuk keterbacaan i + = langkah harus di bagian kontrol. Dalam jika Anda akan melangkah = 0
Mikkel Christiansen
1
Sementara itu akan membantu keterbacaan kode yang baik, saya ingin menekankan cacat pada versi yang salah
kfsone
9
Ada beberapa cara untuk menulis segala jenis kode (biasanya), kebetulan ada dua cara dalam kasus ini (tiga jika Anda menghitung <= dan> =).
Dalam hal ini, orang lebih suka> dan <untuk memastikan bahwa bahkan jika sesuatu yang tidak terduga terjadi dalam loop (seperti bug), itu tidak akan berulang tanpa batas (BAD). Pertimbangkan kode berikut, misalnya.
for(int i =1; i !=3; i++){//More Code
i =5;//OOPS! MISTAKE!//More Code}
Jika kita menggunakan (i <3), kita akan aman dari infinite loop karena menempatkan batasan yang lebih besar.
Ini benar-benar pilihan Anda apakah Anda ingin kesalahan dalam program Anda untuk mematikan semuanya atau tetap berfungsi dengan bug di sana.
seseorang dapat berargumen bahwa infinite loop akan menjadi indikator kesalahan yang baik, tetapi kemudian yang lain akan berpendapat bahwa i = 5 belum tentu merupakan kesalahan
njzk2
7
Alasan paling umum untuk digunakan <adalah konvensi. Lebih banyak programmer menganggap loop seperti ini sebagai "ketika indeks berada dalam kisaran" daripada "sampai indeks mencapai akhir." Ada nilai yang menempel pada konvensi ketika Anda bisa.
Di sisi lain, banyak jawaban di sini mengklaim bahwa menggunakan <formulir membantu menghindari bug. Saya berpendapat bahwa dalam banyak kasus ini hanya membantu menyembunyikan bug. Jika indeks loop seharusnya mencapai nilai akhir, dan, sebaliknya, itu benar-benar melampaui itu, maka ada sesuatu yang terjadi yang tidak Anda duga yang dapat menyebabkan kegagalan fungsi (atau menjadi efek samping dari bug lain). The <kemungkinan akan menunda penemuan bug. Itu!= lebih cenderung mengarah ke kios, hang, atau bahkan crash, yang akan membantu Anda menemukan bug lebih cepat. Semakin cepat bug ditemukan, semakin murah untuk memperbaikinya.
Perhatikan bahwa konvensi ini khusus untuk pengindeksan array dan vektor. Saat melintasi hampir semua jenis struktur data lainnya, Anda akan menggunakan iterator (atau pointer) dan memeriksa langsung untuk nilai akhir. Dalam hal ini Anda harus yakin iterator akan mencapai dan tidak melampaui nilai akhir yang sebenarnya.
Misalnya, jika Anda melangkah melalui string C biasa, biasanya lebih umum untuk menulis:
for(char*p = foo;*p !='\0';++p){// do something with *p}
dari
int length = strlen(foo);for(int i =0; i < length;++i){// do something with foo[i]}
Untuk satu hal, jika string sangat panjang, bentuk kedua akan lebih lambat karena yang strlenlain melewati string.
Dengan string C ++ std ::, Anda akan menggunakan rentang berbasis untuk loop, algoritma standar, atau iterator, meskipun panjangnya tersedia. Jika Anda menggunakan iterator, konvensi ini adalah untuk menggunakan !=daripada <, seperti pada:
for(auto it = foo.begin(); it != foo.end();++it){...}
Demikian pula, iterasi pohon atau daftar atau deque biasanya melibatkan menonton pointer nol atau sentinel lainnya daripada memeriksa apakah indeks tetap dalam jangkauan.
Anda benar untuk menekankan pentingnya idiom dalam pemrograman. Jika saya melihat beberapa kode dan memiliki pola yang umum, saya tidak perlu membuang waktu untuk menyimpulkan polanya, tetapi bisa langsung ke inti dari itu. Saya kira itulah pegangan utama saya dengan perbandingan Yoda - mereka tidak terlihat idiomatis, jadi saya akhirnya harus membacanya dua kali untuk memastikan bahwa mereka memaksudkan apa yang saya pikir mereka maksudkan.
Toby Speight
7
Salah satu alasan untuk tidak menggunakan konstruk ini adalah angka floating point. !=adalah perbandingan yang sangat berbahaya untuk digunakan dengan pelampung karena jarang akan mengevaluasi ke true bahkan jika angkanya terlihat sama. <atau >menghilangkan risiko ini.
Jika loop iterator Anda adalah angka floating point, maka !=lawannya <adalah yang paling sedikit masalah Anda.
Lundin
7
Ada dua alasan terkait untuk mengikuti praktik ini yang keduanya berkaitan dengan fakta bahwa bahasa pemrograman, bagaimanapun, adalah bahasa yang akan dibaca oleh manusia (antara lain).
(1) Sedikit redundansi. Dalam bahasa alami, kami biasanya memberikan lebih banyak informasi daripada yang diperlukan, seperti kode koreksi kesalahan. Di sini informasi tambahannya adalah variabel loop i(lihat bagaimana saya menggunakan redundansi di sini? Jika Anda tidak tahu apa arti 'variabel loop', atau jika Anda lupa nama variabelnya, setelah membaca "variabel loop i", Anda memiliki informasi) kurang dari 5 selama loop, tidak hanya berbeda dari 5. Redundansi meningkatkan keterbacaan.
(2) Konvensi. Bahasa memiliki cara standar spesifik untuk mengekspresikan situasi tertentu. Jika Anda tidak mengikuti cara yang mapan untuk mengatakan sesuatu, Anda masih akan dipahami, tetapi upaya untuk penerima pesan Anda lebih besar karena optimisasi tertentu tidak akan berhasil. Contoh:
Kalimat pertama adalah terjemahan harfiah dari idiom Jerman. Yang kedua adalah idiom bahasa Inggris yang umum dengan kata-kata utama diganti dengan sinonim. Hasilnya dapat dipahami tetapi membutuhkan waktu lebih lama untuk memahami daripada ini:
Jangan bertele-tele. Jelaskan saja masalahnya!
Ini benar bahkan dalam kasus sinonim yang digunakan dalam versi pertama terjadi agar sesuai dengan situasi lebih baik daripada kata-kata konvensional dalam idiom bahasa Inggris. Kekuatan serupa berlaku ketika pemrogram membaca kode. Ini juga mengapa 5 != idan ini 5 > iadalah cara aneh untuk meletakkannya kecuali jika Anda bekerja di lingkungan yang standar untuk bertukar yang lebih normal i != 5dan i < 5dengan cara ini. Komunitas-komunitas dialek semacam itu memang ada, mungkin karena konsistensi membuatnya lebih mudah untuk diingat 5 == idaripada yang alami tetapi rawan kesalahan i == 5.
Ausgezeichnet . Demikian pula, seseorang tidak akan menulis tes sebagai i < 17+(36/-3)(bahkan ketika ini adalah konstanta yang digunakan di tempat lain; maka Anda harus menuliskan nama mereka untuk kejelasan!).
usr2564301
6
Menggunakan perbandingan relasional dalam kasus seperti itu lebih merupakan kebiasaan yang populer daripada yang lain. Ini mendapatkan popularitasnya kembali pada masa ketika pertimbangan konseptual seperti kategori iterator dan perbandingan mereka tidak dianggap prioritas tinggi.
Saya akan mengatakan bahwa orang harus lebih suka menggunakan perbandingan kesetaraan daripada perbandingan relasional bila memungkinkan, karena perbandingan kesetaraan memaksakan persyaratan yang lebih sedikit pada nilai yang dibandingkan. Menjadi EqualityComparable adalah persyaratan yang lebih rendah daripada menjadi LessThanComparable .
Contoh lain yang menunjukkan penerapan perbandingan kesetaraan yang lebih luas dalam konteks semacam itu adalah teka-teki populer dengan penerapan unsignediterasi hingga 0. Itu bisa dilakukan sebagai
for(unsigned i =42; i !=-1;--i)...
Perhatikan bahwa hal di atas sama-sama berlaku untuk iterasi yang ditandatangani dan tidak ditandatangani, sementara versi relasional rusak dengan tipe yang tidak ditandatangani.
Selain contoh-contoh, di mana variabel loop akan (tidak disengaja) berubah di dalam tubuh, ada reasionasi lain untuk menggunakan operator yang lebih kecil dari atau lebih besar:
Peluru kedua paling banter adalah alasan yang sembrono. Kode harus benar dan jelas. Kompak jauh lebih tidak penting.
Jonathan Leffler
@JonathanLeffler Nah, dalam TDD REPL, karakter tambahan itu satu nano-detik ekstra untuk penguraian, dan dikali satu miliar iterasi untuk menemukan bug yang disebabkan oleh tulisan 5 != $i, yang hanya menghabiskan satu detik dalam hidup saya. Uh ... kekek
uskup
1
Selain berbagai orang yang telah menyebutkan bahwa ia mengurangi risiko, itu juga mengurangi jumlah kelebihan fungsi yang diperlukan untuk berinteraksi dengan berbagai komponen perpustakaan standar. Sebagai contoh, jika Anda ingin jenis Anda dapat disimpan dalam std::set, atau digunakan sebagai kunci untuk std::map, atau digunakan dengan beberapa algoritma pencarian dan pengurutan, perpustakaan standar biasanya digunakan std::lessuntuk membandingkan objek karena kebanyakan algoritma hanya membutuhkan urutan lemah yang ketat . Dengan demikian, menjadi kebiasaan yang baik untuk menggunakan <perbandingan alih-alih !=perbandingan (di mana masuk akal, tentu saja).
Anda mungkin benar tentang jumlah kelebihan beban, tetapi ketika mempertimbangkan persyaratan pada objek, maka untuk hampir semua objek, seseorang dapat mendefinisikan !=operator, tetapi tidak selalu mungkin untuk menentukan urutan lemah yang ketat. Dalam hal ini !=akan lebih baik, karena menempatkan persyaratan lebih sedikit pada jenisnya. Namun, saya masih tetap dengan <.
idclev 463035818
0
Tidak ada masalah dari perspektif sintaksis, tetapi logika di balik ekspresi 5!=iitu tidak sehat.
Menurut pendapat saya, menggunakan != untuk mengatur batas-batas loop for tidak logis karena loop for meningkatkan atau mengurangi indeks iterasi, jadi mengatur loop untuk beralih sampai indeks iterasi menjadi di luar batas ( !=untuk sesuatu) bukan implementasi yang tepat.
Ini akan bekerja, tetapi rentan terhadap perilaku sejak penanganan data batas hilang ketika menggunakan !=untuk masalah tambahan (yang berarti bahwa Anda tahu dari awal jika penambahan atau decrements), itu sebabnya bukan !=yang <>>==>digunakan.
Logikanya baik-baik saja. Ketika iadalah 5pintu keluar lingkaran. Apakah Anda bermaksud mengatakan sesuatu yang lain?
Dan Getz
1
Jika data tidak dapat ditransfer dengan benar karena panas, electro.magnetic memengaruhi kode Anda berjalan selamanya. Jika Anda melakukan ini pada workstation atau server biasa dengan RAM ECC tidak ada masalah (baik logis, teknis maupun fisik)
i++
menjadii+=2
(misalnya), itu akan berjalan untuk waktu yang sangat lama (atau mungkin selamanya). Sekarang, karena Anda biasanya menggunakan<
untuk kasus-kasus di mana Anda meningkatkan iterator lebih dari 1, Anda mungkin juga menggunakan<
untuk kasus di mana Anda menambahnya dengan 1 (untuk konsistensi).5 != i
itu jahatif ( i == 5 ) ...
danif ( i = 5 )
. Hal yang sangat berbeda. Membalik operan mencegah masalah: karena literal tidaklvals
, mereka tidak dapat ditugaskan dan kompiler melemparkan pada kesalahan ketik. @Zingam: pemrograman defensif yang bagus!Jawaban:
Sekarang jam 6:31 sore ... Sial, sekarang kesempatan berikutnya untuk pulang adalah besok! :)
Ini untuk menunjukkan bahwa pembatasan yang lebih kuat memitigasi risiko dan mungkin lebih intuitif untuk dipahami.
sumber
<
akan menyembunyikan bug tetapi menggunakan!=
akan membuat jelas bahwa ada masalah.Tidak ada alasan teknis. Tetapi ada mitigasi risiko, rawatan dan pemahaman kode yang lebih baik.
<
atau>
pembatasan yang lebih kuat daripada!=
dan memenuhi tujuan yang sama persis dalam banyak kasus (saya bahkan akan mengatakan dalam semua kasus praktis).Ada pertanyaan rangkap di sini ; dan satu jawaban yang menarik .
sumber
Ya ada alasannya. Jika Anda menulis (berbasis indeks lama polos) untuk loop seperti ini
maka itu berfungsi seperti yang diharapkan untuk nilai apa pun dari
a
danb
(yaitu nol iterasi ketikaa > b
bukannya tak terbatas jika Anda telah menggunakani == b;
).Di sisi lain, untuk iterator Anda akan menulis
karena setiap iterator harus mengimplementasikan suatu
operator!=
, tetapi tidak untuk setiap iterator dimungkinkan untuk menyediakanoperator<
.Juga berbasis rentang untuk loop
bukan hanya gula mewah, tetapi mereka secara terukur mengurangi peluang untuk menulis kode yang salah.
sumber
!=
bukannya<
. Saya pribadi tidak pernah menggunakan yang saya pikir.for (int i=a; i != b; i++) {}
!=
dengan iterator cukup berbahaya, karena kadang - kadang iterator dapat lebih sedikit dibandingkan (misalnya pointer) tetapi perbandingannya tidak ada artinya (ini adalah daftar tertaut).Anda dapat memiliki sesuatu seperti
Jika variabel loop Anda ditulis oleh kode bagian dalam, variabel tersebut
i!=5
mungkin tidak memecah loop tersebut. Ini lebih aman untuk memeriksa ketimpangan.Edit tentang keterbacaan. Bentuk ketimpangan jauh lebih sering digunakan. Oleh karena itu, ini sangat cepat dibaca karena tidak ada yang istimewa untuk dipahami (beban otak berkurang karena tugasnya sama). Jadi keren bagi pembaca untuk memanfaatkan kebiasaan ini.
sumber
Dan last but not least, ini disebut pemrograman defensif , yang berarti untuk selalu mengambil kasus terkuat untuk menghindari kesalahan saat ini dan masa depan yang mempengaruhi program.
Satu-satunya kasus di mana pemrograman defensif tidak diperlukan adalah di mana negara telah dibuktikan oleh pra dan pasca-kondisi (tapi kemudian, membuktikan ini adalah yang paling defensif dari semua pemrograman).
sumber
int
untuk suatui != 15
kondisi, penghitung akan berjalan untuk waktu yang lama jika ada sesuatu di atas bit keempat dibalik, terutama pada mesinsizeof(int)
yang 64. , atau dalam superkomputer besar (karena begitu banyak memori yang ada).Saya berpendapat bahwa ungkapan itu seperti
lebih ekspresif dari niat daripada apa adanya
Yang pertama dengan jelas menyatakan bahwa kondisi tersebut merupakan ujian untuk batas atas eksklusif pada rentang; yang terakhir adalah tes biner dari kondisi keluar. Dan jika badan loop adalah non-sepele, mungkin tidak jelas bahwa indeks hanya dimodifikasi dalam
for
pernyataan itu sendiri.sumber
Iterator adalah kasus penting ketika Anda paling sering menggunakan
!=
notasi:Memang: dalam praktiknya saya akan menulis hal yang sama dengan mengandalkan
range-for
:tetapi intinya tetap: orang biasanya membandingkan iterator menggunakan
==
atau!=
.sumber
!=
untuk mereka. Misalnya, dalamstd::vector
Anda dapat menggunakan<
sebagai iterator terikat ke indeks / pointer, tetapi dalamstd::set
tidak ada urutan yang ketat, karena berjalan pohon biner.Kondisi loop adalah invarian loop yang dipaksakan.
Misalkan Anda tidak melihat isi loop:
dalam hal ini, Anda tahu pada awal iterasi loop yang
i
tidak sama5
.dalam hal ini, Anda tahu pada awal iterasi loop yang
i
kurang dari5
.Yang kedua jauh, jauh lebih banyak informasi daripada yang pertama, bukan? Sekarang, maksud programmer adalah (hampir pasti) sama, tetapi jika Anda mencari bug, memiliki kepercayaan diri dari membaca baris kode adalah hal yang baik. Dan yang kedua menegakkan invarian itu, yang berarti beberapa bug yang akan menggigit Anda dalam kasus pertama tidak dapat terjadi (atau tidak menyebabkan kerusakan memori, katakanlah) dalam kasus kedua.
Anda tahu lebih banyak tentang keadaan program, dari membaca lebih sedikit kode,
<
daripada dengan!=
. Dan pada CPU modern, mereka mengambil jumlah waktu yang sama karena tidak ada perbedaan.Jika Anda
i
tidak dimanipulasi dalam tubuh loop, dan itu selalu meningkat sebesar 1, dan itu mulai kurang dari5
, tidak akan ada perbedaan. Tetapi untuk mengetahui apakah itu dimanipulasi, Anda harus mengkonfirmasi masing-masing fakta ini.Beberapa fakta ini relatif mudah, tetapi Anda bisa salah. Namun, memeriksa seluruh tubuh loop itu menyebalkan.
Di C ++ Anda bisa menulis
indexes
tipe seperti itu:melakukan hal yang sama seperti salah satu dari dua
for
loop di atas , bahkan ke kompiler mengoptimalkannya ke kode yang sama. Di sini, bagaimanapun, Anda tahu bahwai
tidak dapat dimanipulasi dalam tubuh loop, seperti yang dinyatakanconst
, tanpa kode merusak memori.Semakin banyak informasi yang Anda dapatkan dari satu baris kode tanpa harus memahami konteksnya, semakin mudah melacak apa yang salah.
<
dalam hal bilangan bulat loop memberi Anda lebih banyak informasi tentang keadaan kode di baris itu daripada yang!=
dilakukan.sumber
Iya; OpenMP tidak memparalelkan loop dengan
!=
kondisi.sumber
Ini mungkin terjadi bahwa variabel
i
diatur ke beberapa nilai besar dan jika Anda hanya menggunakan!=
operator Anda akan berakhir dalam loop tanpa akhir.sumber
i
diam-diam akan membungkus ketika maksimal. Tapi ya, kemungkinan besar lebih lama dari yang Anda siap tunggu.Seperti yang dapat Anda lihat dari banyak jawaban lainnya, ada alasan untuk menggunakan <daripada! = Yang akan membantu dalam kasus tepi, kondisi awal, modifikasi penghitung putaran yang tidak diinginkan, dll ...
Jujur saja, saya tidak berpikir Anda bisa menekankan pentingnya konvensi. Untuk contoh ini akan cukup mudah bagi programmer lain untuk melihat apa yang Anda coba lakukan, tetapi itu akan menyebabkan pengambilan ganda. Salah satu pekerjaan saat pemrograman membuatnya menjadi dapat dibaca dan akrab bagi semua orang mungkin, jadi pasti ketika seseorang harus memperbarui / mengubah kode Anda, tidak perlu banyak usaha untuk mencari tahu apa yang Anda lakukan dalam blok kode yang berbeda . Jika saya melihat seseorang menggunakan
!=
, saya akan berasumsi ada alasan mereka menggunakannya bukan<
dan jika itu adalah loop besar saya akan melihat seluruh hal mencoba untuk mencari tahu apa yang Anda lakukan yang membuat itu perlu ... dan itu membuang-buang waktu.sumber
Seperti yang sudah dikatakan oleh Ian Newson, Anda tidak bisa dengan andal mengulang variabel mengambang dan keluar bersama
!=
. Misalnya,benar-benar akan berulang selamanya, karena 0,1 tidak dapat secara tepat diwakili dalam floating point, maka penghitungnya akan meleset 1. With
<
itu berakhir.(Namun perlu dicatat bahwa pada dasarnya itu adalah perilaku yang tidak ditentukan apakah Anda mendapatkan 0,9999 ... sebagai nomor yang diterima terakhir - jenis pelanggaran yang kurang dari asumsi - atau sudah keluar di 1,0000000000000001000).
sumber
Saya mengambil kata sifat "teknis" berarti perilaku bahasa / keanehan dan efek samping kompiler seperti kinerja kode yang dihasilkan.
Untuk tujuan ini, jawabannya adalah: tidak (*). (*) Adalah "silakan baca manual prosesor Anda". Jika Anda bekerja dengan sistem RISC atau FPGA case-edge, Anda mungkin perlu memeriksa instruksi apa yang dihasilkan dan berapa biayanya. Tapi jika Anda menggunakan hampir semua arsitektur modern konvensional, maka tidak ada perbedaan tingkat prosesor yang signifikan dalam biaya antara
lt
,eq
,ne
dangt
.Jika Anda menggunakan kasus tepi Anda bisa menemukan bahwa
!=
memerlukan tiga operasi (cmp
,not
,beq
) vs dua (cmp
,blt xtr myo
). Sekali lagi, RTM dalam hal itu.Sebagian besar, alasannya defensif / pengerasan, terutama ketika bekerja dengan pointer atau loop kompleks. Mempertimbangkan
Contoh yang kurang dibuat-buat adalah di mana Anda menggunakan nilai balik untuk melakukan peningkatan, menerima data dari pengguna:
Coba ini dan masukkan nilai 1, 2, 10, 999.
Anda dapat mencegah ini:
Tapi yang mungkin Anda inginkan adalah
Ada juga sesuatu yang bias konvensi terhadap
<
, karena pemesanan dalam wadah standar sering bergantungoperator<
, misalnya hashing dalam beberapa wadah STL menentukan kesetaraan dengan mengatakanJika
lhs
danrhs
adalah kelas yang ditentukan pengguna menulis kode ini sebagaiImplementor harus menyediakan dua fungsi perbandingan. Jadi
<
sudah menjadi operator yang disukai.sumber
Ada beberapa cara untuk menulis segala jenis kode (biasanya), kebetulan ada dua cara dalam kasus ini (tiga jika Anda menghitung <= dan> =).
Dalam hal ini, orang lebih suka> dan <untuk memastikan bahwa bahkan jika sesuatu yang tidak terduga terjadi dalam loop (seperti bug), itu tidak akan berulang tanpa batas (BAD). Pertimbangkan kode berikut, misalnya.
Jika kita menggunakan (i <3), kita akan aman dari infinite loop karena menempatkan batasan yang lebih besar.
Ini benar-benar pilihan Anda apakah Anda ingin kesalahan dalam program Anda untuk mematikan semuanya atau tetap berfungsi dengan bug di sana.
Semoga ini bisa membantu!
sumber
Alasan paling umum untuk digunakan
<
adalah konvensi. Lebih banyak programmer menganggap loop seperti ini sebagai "ketika indeks berada dalam kisaran" daripada "sampai indeks mencapai akhir." Ada nilai yang menempel pada konvensi ketika Anda bisa.Di sisi lain, banyak jawaban di sini mengklaim bahwa menggunakan
<
formulir membantu menghindari bug. Saya berpendapat bahwa dalam banyak kasus ini hanya membantu menyembunyikan bug. Jika indeks loop seharusnya mencapai nilai akhir, dan, sebaliknya, itu benar-benar melampaui itu, maka ada sesuatu yang terjadi yang tidak Anda duga yang dapat menyebabkan kegagalan fungsi (atau menjadi efek samping dari bug lain). The<
kemungkinan akan menunda penemuan bug. Itu!=
lebih cenderung mengarah ke kios, hang, atau bahkan crash, yang akan membantu Anda menemukan bug lebih cepat. Semakin cepat bug ditemukan, semakin murah untuk memperbaikinya.Perhatikan bahwa konvensi ini khusus untuk pengindeksan array dan vektor. Saat melintasi hampir semua jenis struktur data lainnya, Anda akan menggunakan iterator (atau pointer) dan memeriksa langsung untuk nilai akhir. Dalam hal ini Anda harus yakin iterator akan mencapai dan tidak melampaui nilai akhir yang sebenarnya.
Misalnya, jika Anda melangkah melalui string C biasa, biasanya lebih umum untuk menulis:
dari
Untuk satu hal, jika string sangat panjang, bentuk kedua akan lebih lambat karena yang
strlen
lain melewati string.Dengan string C ++ std ::, Anda akan menggunakan rentang berbasis untuk loop, algoritma standar, atau iterator, meskipun panjangnya tersedia. Jika Anda menggunakan iterator, konvensi ini adalah untuk menggunakan
!=
daripada<
, seperti pada:Demikian pula, iterasi pohon atau daftar atau deque biasanya melibatkan menonton pointer nol atau sentinel lainnya daripada memeriksa apakah indeks tetap dalam jangkauan.
sumber
Salah satu alasan untuk tidak menggunakan konstruk ini adalah angka floating point.
!=
adalah perbandingan yang sangat berbahaya untuk digunakan dengan pelampung karena jarang akan mengevaluasi ke true bahkan jika angkanya terlihat sama.<
atau>
menghilangkan risiko ini.sumber
!=
lawannya<
adalah yang paling sedikit masalah Anda.Ada dua alasan terkait untuk mengikuti praktik ini yang keduanya berkaitan dengan fakta bahwa bahasa pemrograman, bagaimanapun, adalah bahasa yang akan dibaca oleh manusia (antara lain).
(1) Sedikit redundansi. Dalam bahasa alami, kami biasanya memberikan lebih banyak informasi daripada yang diperlukan, seperti kode koreksi kesalahan. Di sini informasi tambahannya adalah variabel loop
i
(lihat bagaimana saya menggunakan redundansi di sini? Jika Anda tidak tahu apa arti 'variabel loop', atau jika Anda lupa nama variabelnya, setelah membaca "variabel loopi
", Anda memiliki informasi) kurang dari 5 selama loop, tidak hanya berbeda dari 5. Redundansi meningkatkan keterbacaan.(2) Konvensi. Bahasa memiliki cara standar spesifik untuk mengekspresikan situasi tertentu. Jika Anda tidak mengikuti cara yang mapan untuk mengatakan sesuatu, Anda masih akan dipahami, tetapi upaya untuk penerima pesan Anda lebih besar karena optimisasi tertentu tidak akan berhasil. Contoh:
Kalimat pertama adalah terjemahan harfiah dari idiom Jerman. Yang kedua adalah idiom bahasa Inggris yang umum dengan kata-kata utama diganti dengan sinonim. Hasilnya dapat dipahami tetapi membutuhkan waktu lebih lama untuk memahami daripada ini:
Ini benar bahkan dalam kasus sinonim yang digunakan dalam versi pertama terjadi agar sesuai dengan situasi lebih baik daripada kata-kata konvensional dalam idiom bahasa Inggris. Kekuatan serupa berlaku ketika pemrogram membaca kode. Ini juga mengapa
5 != i
dan ini5 > i
adalah cara aneh untuk meletakkannya kecuali jika Anda bekerja di lingkungan yang standar untuk bertukar yang lebih normali != 5
dani < 5
dengan cara ini. Komunitas-komunitas dialek semacam itu memang ada, mungkin karena konsistensi membuatnya lebih mudah untuk diingat5 == i
daripada yang alami tetapi rawan kesalahani == 5
.sumber
i < 17+(36/-3)
(bahkan ketika ini adalah konstanta yang digunakan di tempat lain; maka Anda harus menuliskan nama mereka untuk kejelasan!).Menggunakan perbandingan relasional dalam kasus seperti itu lebih merupakan kebiasaan yang populer daripada yang lain. Ini mendapatkan popularitasnya kembali pada masa ketika pertimbangan konseptual seperti kategori iterator dan perbandingan mereka tidak dianggap prioritas tinggi.
Saya akan mengatakan bahwa orang harus lebih suka menggunakan perbandingan kesetaraan daripada perbandingan relasional bila memungkinkan, karena perbandingan kesetaraan memaksakan persyaratan yang lebih sedikit pada nilai yang dibandingkan. Menjadi EqualityComparable adalah persyaratan yang lebih rendah daripada menjadi LessThanComparable .
Contoh lain yang menunjukkan penerapan perbandingan kesetaraan yang lebih luas dalam konteks semacam itu adalah teka-teki populer dengan penerapan
unsigned
iterasi hingga0
. Itu bisa dilakukan sebagaiPerhatikan bahwa hal di atas sama-sama berlaku untuk iterasi yang ditandatangani dan tidak ditandatangani, sementara versi relasional rusak dengan tipe yang tidak ditandatangani.
sumber
Selain contoh-contoh, di mana variabel loop akan (tidak disengaja) berubah di dalam tubuh, ada reasionasi lain untuk menggunakan operator yang lebih kecil dari atau lebih besar:
<
atau>
hanya satu arang, tetapi!=
duasumber
5 != $i
, yang hanya menghabiskan satu detik dalam hidup saya. Uh ... kekekSelain berbagai orang yang telah menyebutkan bahwa ia mengurangi risiko, itu juga mengurangi jumlah kelebihan fungsi yang diperlukan untuk berinteraksi dengan berbagai komponen perpustakaan standar. Sebagai contoh, jika Anda ingin jenis Anda dapat disimpan dalam
std::set
, atau digunakan sebagai kunci untukstd::map
, atau digunakan dengan beberapa algoritma pencarian dan pengurutan, perpustakaan standar biasanya digunakanstd::less
untuk membandingkan objek karena kebanyakan algoritma hanya membutuhkan urutan lemah yang ketat . Dengan demikian, menjadi kebiasaan yang baik untuk menggunakan<
perbandingan alih-alih!=
perbandingan (di mana masuk akal, tentu saja).sumber
!=
operator, tetapi tidak selalu mungkin untuk menentukan urutan lemah yang ketat. Dalam hal ini!=
akan lebih baik, karena menempatkan persyaratan lebih sedikit pada jenisnya. Namun, saya masih tetap dengan<
.Tidak ada masalah dari perspektif sintaksis, tetapi logika di balik ekspresi
5!=i
itu tidak sehat.Menurut pendapat saya, menggunakan
!=
untuk mengatur batas-batas loop for tidak logis karena loop for meningkatkan atau mengurangi indeks iterasi, jadi mengatur loop untuk beralih sampai indeks iterasi menjadi di luar batas (!=
untuk sesuatu) bukan implementasi yang tepat.Ini akan bekerja, tetapi rentan terhadap perilaku sejak penanganan data batas hilang ketika menggunakan
!=
untuk masalah tambahan (yang berarti bahwa Anda tahu dari awal jika penambahan atau decrements), itu sebabnya bukan!=
yang<>>==>
digunakan.sumber
i
adalah5
pintu keluar lingkaran. Apakah Anda bermaksud mengatakan sesuatu yang lain?