'For' döngüsünde 1 ile artırılırken! = Yerine> (<) kullanmanın teknik bir nedeni var mı?


198

Neredeyse hiç böyle bir fordöngü görmüyorum :

for (int i = 0; 5 != i; ++i)
{}

Kullanmak için teknik bir nedeni var mı >yoksa <yerine !=bir de 1'den başlayarak zaman fordöngü? Yoksa bu daha çok bir kongre midir?


104
Hiç değiştirmez eğer, daha okunabilir hale getirir, artı i++için i+=2(örneğin), o (sonsuza muhtemelen ya) çok uzun bir süre boyunca çalışacaktır. Şimdi, <yineleyiciyi 1'den fazla artırdığınız durumlarda genellikle kullandığınız için , 1 ile artırdığınız <durumda da kullanabilirsiniz (tutarlılık için).
barak manos

112
5 != ikötü
Slava

27
Her zaman ne yaptığınızın bilincinde olmalısınız, ama yine de hatalar yapacaksınız. <Kullanılması, birisinin bu koda hata girme olasılığını azaltır.
Aurast

40
@OleTange Eğer kayan nokta sayıları kullanarak yineleme yapıyorsanız zaten vidalı ..
CaptainCodeman

29
@Slava ... kötü değil. Görünüşe göre if ( i == 5 ) ...ve arasındaki farkı yaratan basit bir yazım hatasıyla C'de hiç bitmediniz if ( i = 5 ). Çok farklı şeyler. İşlenenleri ters çevirmek sorunu önler: değişmez değerler olmadığından lvals, atanamazlar ve derleyici yazım hatası yapar. @Zingam: iyi savunma programları!
Nicholas Carey

Yanıtlar:


303
while (time != 6:30pm) {
    Work();
}

18:31 ... Kahretsin, şimdi bir sonraki eve gitmek için şansım yarın! :)

Bu, daha güçlü kısıtlamanın riskleri azalttığını ve muhtemelen anlaşılması daha sezgisel olduğunu göstermektedir.


25
Bazen, "riskleri azaltmaya" çalışmak hatayı gizler. Döngünün tasarımının saat 18: 30'da fark edilmeden kaymasını engellemesi gerekiyorsa, kullanmak <hatayı gizler, ancak kullanmak !=bir sorun olduğunu açıkça gösterir.
Adrian McCarthy

27
@AdrianMcCarthy: Mutlaka değil; tanıyı zorlaştırarak ikinci bir hata verebilir .
Yörüngedeki Hafiflik Yarışları

4
@AdrianMcCarthy: Bu benim açımdan; henüz görmediğiniz birkaç örneğiniz olabilir;)
Orbit'teki Hafiflik Yarışları

6
Yineleyiciler bence @AdrianMcCarthy noktasının mükemmel bir örneğidir. Onlar için önerilen karşılaştırma <yerine! = 'Dir.
Taekahn

5
Tam olarak bu hatayı gördüm (ve 3 ay hata ayıklamaya neden oldu) - ama bu cevap tamamen noktayı kaçırıyor. Verilen örnekte , son durumun kaçırılması imkansızdır . Hatta bilinçli bir şekilde! = Over <'i seçmenin bu gerçeğin güçlü bir iddiasını yapmak olduğunu bile söyleyebilirsiniz. Kesin olmayan bir riski azaltmak benim için bir kod kokusu. (Bunu söyledikten sonra, <deyimsel olduğunu, bunu herhangi bir şekilde kullanmak için iyi bir neden olduğunu eşit derecede tartışabilirsiniz.)
Ian Goldby

95

Teknik bir sebep yok. Ancak risk, sürdürülebilirlik ve kodun daha iyi anlaşılması için hafifletme vardır.

<ya >da !=çoğu durumda aynı amacı daha güçlü kısıtlamalara uyuyor ve tam olarak yerine getiriyorlar (tüm pratik durumlarda bile söyleyebilirim).

Burada yinelenen bir soru var ; ve ilginç bir cevap .


6
Yineleyiciler gibi <veya> desteklemeyen, ancak == ve! = Desteklemeyen bazı türler vardır.
Simon B

1
İnt ile bir for döngüsü . Yineleyici yok.
Ely

7
"Ancak risk, sürdürülebilirlik ve kodun daha iyi anlaşılması için hafifletme var." Bunların hepsi, teknik nedenlerdir. :-)
TJ Crowder

@TJCrowder Makinelerin sonuç olarak ne yapacağından bahsetmek istediğinizde ne tür bir sebep var?
Brilliand

1
@DanSheppard Genelde risk ve sürdürülebilirliğin azaltılmasının ticari nedenler olduğunu ve kodun sosyal bir neden olarak daha iyi anlaşılmasını (bu nedenlerin hepsi bu durumda teknik bir konuya uygulanmasına rağmen) düşünürüm. "Riskin azaltılması" hususları hiçbir şekilde teknik konularla sınırlı değildir ve kendinizi farklı bir grup insanla çalışırken bulursanız (ilgili makineler hiç değişmese bile) "daha iyi kod anlayışı" hususları değişebilir ).
Brilliand

85

Evet, bir nedeni var. Böyle bir döngü için (düz eski dizin tabanlı) yazarsanız

for (int i = a; i < b; ++i){}

Herhangi değerleri için beklendiği gibi o zaman çalışır ave b(yani sıfır tekrarlamalar a > byerine sonsuzun kullandığınız olsaydı i == b;).

Öte yandan, yineleyiciler için

for (auto it = begin; it != end; ++it) 

çünkü herhangi bir yineleyici bir uygulamalıdır operator!=, ancak her yineleyici için bir operator<.

Ayrıca döngüler için menzil tabanlı

for (auto e : v)

sadece süslü şeker değil, aynı zamanda yanlış kod yazma şansını ölçülebilir şekilde azaltırlar.


4
Güzel bir örnek. Bunun !=yerine bir davaya ilgi duyarım <. Şahsen hiç düşünmediğimi kullanmadım.
Ely

@Elyasin İyi bir tane bulamadım ve kötü bir tane yayınlamak istemedim: N x kabının büyüklüğünü + x modulo artırarak ve döngüyü durdurmak istediğinizde bir çeşit dairesel kabınız olduğunu hayal edin belli bir endekse ulaşmak .... bu gerçekten kötü bir örnek. Belki daha iyi bir tane bulacağım
idclev 463035818

<Yerine! = İle aynı döngü, bu bağlamda <(veya>) avantajının ne olduğunu netleştirir. for (int i=a; i != b; i++) {}
Paul Smith

10
!=Yineleyicilerin yanı sıra herhangi bir şey kullanmak oldukça tehlikelidir, çünkü bazen yineleyiciler karşılaştırıldığından daha az olabilir (örneğin bir işaretçi), ancak karşılaştırma anlamsızdır (bağlantılı bir listedir).
Zan Lynx

1
Beyaz alanı ciddi şekilde kullanmayı öğrenin.
Miles Rout

70

Gibi bir şey olabilir

for(int i = 0; i<5; ++i){
    ...
    if(...) i++;
    ...
}

Döngü değişkeniniz iç kod tarafından yazıldıysa, i!=5bu döngü kırılmayabilir. Eşitsizliği kontrol etmek daha güvenlidir.

Okunabilirlik hakkında düzenleme yapın . Eşitsizlik formu çok daha sık kullanılır. Bu nedenle, anlaşılması gereken özel bir şey olmadığı için bunu okumak çok hızlıdır (görev yaygın olduğu için beyin yükü azalır). Bu yüzden okuyucuların bu alışkanlıklardan faydalanması harika.


6
Bu tip iç "if (koşul) o zaman i ++" ilk düşündüğüm şey.
WernerCD

3
Bunun en çok oylanan cevap olmasını bekliyordu; Onu bulmak için bu kadar kaydırmam gerektiğine şaşırdım. Bu acemi bir programcıyı "en güçlü koşulu kullanmalısınız" dan ikna etmek için çok daha fazlasını yapar. Diğer cevaplar, eğer üstte kalırlarsa, bunu OP'nin önerdiği kodda neyin yanlış gidebileceğinin açık ve açık bir açıklaması olarak dahil etmelidir.
msouth

1
@msouth Tamamen katılıyorum, ancak POV'um oldukça öznel;)
johan d

3
@msouth Beklenmedik üretim davranışları hatalarımı ortaya çıkardığında seviyorum, değil mi? :-)
deworde

3
@msouth Bak, tek yapmamız gereken hiçbir zaman hata yapmamak ve her şey yoluna girecek. Sade.
deworde

48

Ve son fakat aynı derecede önemli olarak, buna savunma programlama denir , yani programı etkileyen mevcut ve gelecekteki hatalardan kaçınmak için her zaman en güçlü durumu ele almak anlamına gelir.

Savunma programlamasına ihtiyaç duyulmayan tek durum, durumların ön ve son koşullar tarafından kanıtlandığı yerlerdir (ancak daha sonra, bunun tüm programlama için en savunmacı olduğunu kanıtlamak).


2
Bunu destekleyen iyi bir örnek: Bellek, radyasyonun neden olduğu bit döndürmelere ( SEU ) karşı savunmasızdır . Bir koşul intiçin kullanılırken i != 15, dördüncü bitin üstündeki herhangi bir şey, özellikle sizeof(int)64 olan makinelerde ters çevrilirse , sayaç uzun süre çalışacaktır. veya büyük süper bilgisayarlarda (çok fazla bellek olduğu için).
Josh Sanford

2
Radyasyonun hafızanızı değiştirirken programınızın iyi çalışacağını düşünmek iyimser bir yol ve anticatastrofik bir düşünme biçimidir ... iyi yorum! :)
Luis Colorado

37

Ben böyle bir ifadenin

for ( int i = 0 ; i < 100 ; ++i )
{
  ...
}

daha kararlı bir ifade olandan

for ( int i = 0 ; i != 100 ; ++i )
{
  ...
}

Birincisi, koşulun bir aralıktaki özel bir üst sınır için bir test olduğunu açıkça belirtmektedir; ikincisi bir çıkış koşulunun ikili testidir. Döngünün gövdesi önemsiz değilse, dizinin yalnızca forifadenin kendisinde değiştirildiği anlaşılamayabilir .


13
"Bu döngünün en fazla 5 kez çalışmasını istiyorum" vs. "Bu döngüyü tam olarak 5 kez istemediğim kadar gerektiği kadar çalıştırmak istiyorum."
bishop

Bir aralıktaki üst sınırı belirtmek için +1. Bunun sayısal aralıklar için önemli olduğunu düşünüyorum. ! =, böyle bir for döngüsünde uygun bir aralık tanımlamıyor
element11

22

!=Gösterimi en sık kullandığınızda yineleyiciler önemli bir durumdur :

for(auto it = vector.begin(); it != vector.end(); ++it) {
 // do stuff
}

Verildi: pratikte ben aynı dayanarak bir range-for:

for(auto & item : vector) {
 // do stuff
}

ancak mesele şudur: normalde yineleyicileri ==veya kullanarak karşılaştırır !=.


2
Yineleyiciler genellikle bir eşitlik / eşitsizlik kavramına sahiptir ve bir düzen değil, bu yüzden !=onlar için kullanıyorsunuz . Örneğin, bir de std::vectorsen olabilir kullanmak <yineleyici endeksi / pointer bağlıdır olarak değil, bir de std::setbir ikili ağaçta yürür gibi böyle katı sipariş var.
Martin

19

Döngü koşulu, zorunlu bir döngü değişmezidir.

Döngünün gövdesine bakmadığınızı varsayalım:

for (int i = 0; i != 5; ++i)
{
  // ?
}

bu durumda, döngü yinelemesinin başlangıcında ieşit olmayan bir şeyi bilirsiniz 5.

for (int i = 0; i < 5; ++i)
{
  // ?
}

bu durumda, döngü yinelemesinin başlangıcından idaha az olduğunu bilirsiniz 5.

İkincisi, birinciden çok daha fazla bilgi, değil mi? Şimdi, programcı niyeti (neredeyse kesinlikle) aynıdır, ancak böcek arıyorsanız, bir kod satırını okumaktan emin olmak iyi bir şeydir. Ve ikincisi bu değişmezi zorlar , yani ilk durumda sizi ısıracak bazı hatalar ikinci durumda gerçekleşemez (veya bellek bozulmasına neden olmaz).

Sen ile, daha az kod okuyarak, programın durumu hakkında daha fazla bilgi edinmek <kıyasla !=. Ve modern CPU'larda, fark olmadan aynı zaman alırlar.

Eğer senin idöngü gövdesinde manipüle değildi ve her zaman 1 ile arttırıldı, ve bunun daha az başlayan5 olsaydı , hiçbir fark olmazdı. Ancak manipüle edilip edilmediğini bilmek için bu gerçeklerin her birini doğrulamanız gerekir.

Bu gerçeklerden bazıları nispeten kolaydır, ancak yanlış olabilirsiniz. Bununla birlikte, döngünün tüm gövdesini kontrol etmek bir acıdır.

C ++ ile şöyle bir indexestür yazabilirsiniz :

for( const int i : indexes(0, 5) )
{
  // ?
}

yukarıdaki iki fordöngüden herhangi biriyle aynı şeyi yapar , hatta derleyiciyi aynı koda kadar optimize eder. Ancak burada, sen biliyor o ida açıkça belirtildiği gibi, döngü gövdesinde manipüle edilemez constkod bozulmasını belleğe olmadan.

Bağlamı anlamak zorunda kalmadan bir kod satırından ne kadar fazla bilgi edinebiliyorsanız, neyin yanlış gittiğini takip etmek o kadar kolay olur. <tamsayı döngülerinde, kodun o satırdaki durumu hakkında olduğundan daha fazla bilgi verir !=.



13

Değişken ibüyük bir değere ayarlanmış olabilir ve sadece !=operatörü kullanırsanız sonsuz bir döngü elde edersiniz.


1
Gerçekten sonsuz değil - çoğu C uygulamasında i, maksimumda sessizce sarılır. Ama evet, büyük olasılıkla beklemeye hazır olduğunuzdan daha uzun.
19.07.2015

12

Diğer sayısız cevaptan da görebileceğiniz gibi, uç durumlarda, başlangıç ​​koşullarında, istenmeyen döngü sayacı modifikasyonunda vb.

Dürüst olmak gerekirse, konvansiyonun önemini yeterince vurgulayabileceğinizi sanmıyorum. Bu örnek için, diğer programcıların ne yapmaya çalıştığınızı görmeleri kolay olacak, ancak bu iki kez alınmasına neden olacaktır. Programlama sırasındaki işlerden biri, onu mümkün olduğunca herkes tarafından okunabilir ve tanıdık hale getirmektir, bu nedenle kaçınılmaz olarak birisinin kodunuzu güncellemesi / değiştirmeniz gerektiğinde, farklı kod bloklarında ne yaptığınızı anlamak çok fazla çaba gerektirmez . Birinin kullandığını !=görürsem, bunun yerine kullanmasının bir nedeni olduğunu varsayardım <ve büyük bir döngü olsaydı, bunu gerekli kılan ne yaptığını anlamaya çalışırken her şeye bakardım ... ve bu boşa zaman.


12

Ian Newson tarafından daha önce de belirtildiği gibi, değişken bir değişken üzerinde güvenilir bir şekilde döngü yapıp çıkamazsınız !=. Örneğin,

for (double x=0; x!=1; x+=0.1) {}

gerçekte sonsuza dek dönecektir, çünkü 0.1 kayan noktada tam olarak temsil edilemez, bu nedenle sayaç 1'i dar olarak özlüyor. < .

(Bununla birlikte , son kabul edilen sayı olarak 0.9999'u almanın - hangi varsayımdan daha azını ihlal eden - veya 1.0000000000000001'de zaten çıkmanın temelde tanımlanmamış bir davranış olduğuna dikkat edin.)


10

"Teknik" sıfatını dil davranışı / tuhaflıkları ve oluşturulan kodun performansı gibi derleyici yan etkilerini kastediyorum.

Bu amaçla cevap: hayır (*). (*) "Lütfen işlemci kılavuzunuza bakın". Bazı kenar kasa RISC veya FPGA sistemi ile çalışıyorsanız, hangi talimatların üretildiğini ve bunların maliyetini kontrol etmeniz gerekebilir. Ancak hemen hemen her türlü geleneksel modern mimariyi kullanıyorsanız, maliyetler arasında önemli bir işlemci seviyesi farkı yoktur.lt , eq, neve gt.

Bir kenar kasası kullanıyorsanız,!= üç operasyonları (gerektirir cmp, not, beqikisi (vs) cmp, blt xtr myo). Yine, bu durumda RTM.

Çoğunlukla, özellikle işaretçilerle veya karmaşık döngülerle çalışırken nedenleri savunma / sertleştirme. Düşünmek

// highly contrived example
size_t count_chars(char c, const char* str, size_t len) {
    size_t count = 0;
    bool quoted = false;
    const char* p = str;
    while (p != str + len) {
        if (*p == '"') {
            quote = !quote;
            ++p;
        }
        if (*(p++) == c && !quoted)
            ++count;
    }
    return count;
}

Daha az anlaşılır bir örnek, artışları gerçekleştirmek ve bir kullanıcıdan veri kabul etmek için dönüş değerlerini kullandığınız durumdur:

#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(;;)
    }
}

Bunu deneyin ve 1, 2, 10, 999 değerlerini girin.

Bunu engelleyebilirsiniz:

#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;
    }
}

Ama muhtemelen istediğin şey

#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;
    }
}

Ayrıca, konvansiyona yönelik bir önyargının da bir <nedeni vardır, çünkü standart kaplarda sipariş vermek sıklıkla kullanılır operator<, örneğin birkaç STL kapında hashleme,

if (lhs < rhs) // T.operator <
    lessthan
else if (rhs < lhs) // T.operator < again
    greaterthan
else
    equal

Eğer lhsve rhskullanıcı tanımlı sınıf bu kodu olarak yazıyoruz

if (lhs < rhs) // requires T.operator<
    lessthan
else if (lhs > rhs) // requires T.operator>
    greaterthan
else
    equal

Uygulayıcı iki karşılaştırma işlevi sağlamalıdır. Böylece <tercih edilen operatör haline geldi.


Okunabilirlik için i + = adımı kontrol bölümünde olmalıdır. Eğer adım = 0
Mikkel Christiansen

1
Bu, iyi kodun okunabilirliğine yardımcı olurken, hatalı sürümdeki kusuru vurgulamak istedim
kfsone

9

Herhangi bir kod yazmanın birkaç yolu vardır (genellikle), bu durumda sadece iki yol olur (<= ve> = sayıyorsanız üç).

Bu durumda, insanlar döngüde beklenmedik bir şey olsa bile (bir hata gibi) sonsuz döngü yapmamasını sağlamak için> ve <tercih ederler. Örneğin, aşağıdaki kodu düşünün.

for (int i = 1; i != 3; i++) {
    //More Code
    i = 5; //OOPS! MISTAKE!
    //More Code
}

Eğer (i <3) kullansaydık, daha büyük bir kısıtlama getirdiği için sonsuz bir döngüden güvende olurduk.

Programınızda her şeyi kapatmak veya orada hata ile çalışmaya devam etmek için bir hata isteyip istemediğiniz gerçekten seçiminiz.

Umarım bu yardımcı oldu!


biri sonsuz döngünün hatanın iyi bir göstergesi olacağını iddia edebilirdi, ama sonra diğeri i = 5'in mutlaka bir hata olmadığını iddia edebilirdi
njzk2

7

Kullanmanın en yaygın nedeni < sözleşmedir. Daha fazla programcı, böyle bir döngüyü "dizin sonuna kadar" yerine "aralıktayken" olarak düşünür. Mümkün olduğunda konvansiyona bağlı kalmak değerdir.

Öte yandan, burada birçok cevap <formu kullanmanın hataların önlenmesine yardımcı olduğunu iddia ediyor . Çoğu durumda bunun sadece böceklerin gizlenmesine yardımcı olduğunu iddia ediyorum . Döngü endeksinin bitiş değerine ulaşması gerekiyorsa ve bunun yerine, aslında bunun ötesine geçerse, o zaman beklemediğiniz ve arızaya neden olabilecek (veya başka bir hatanın yan etkisi olabilecek) bir şey var. Büyük <olasılıkla hatanın bulunmasını geciktirecektir. !=Er hata nokta yardımcı olacak bir durak, asmak, hatta bir kaza, yol açma olasılığı daha yüksektir. Bir hata ne kadar erken bulunursa, düzeltilmesi o kadar ucuz olur.

Bu kuralın dizi ve vektör indekslemesine özgü olduğunu unutmayın. Hemen hemen her tür veri yapısını gezerken, bir yineleyici (veya işaretçi) kullanır ve doğrudan bir bitiş değeri olup olmadığını kontrol edersiniz. Bu gibi durumlarda, yineleyicinin gerçek son değere ulaşmadığından ve bu değeri aşmadığından emin olmalısınız.

Örneğin, düz bir C dizesinden geçiyorsanız, genellikle yazmak daha yaygındır:

for (char *p = foo; *p != '\0'; ++p) {
  // do something with *p
}

göre

int length = strlen(foo);
for (int i = 0; i < length; ++i) {
  // do something with foo[i]
}

Birincisi, eğer dize çok uzunsa, ikinci form daha yavaş olacaktır, çünkü strlendize içinden bir başka geçiştir.

C ++ std :: dizgisinde, uzunluk hazır olsa bile döngü için aralık tabanlı, standart bir algoritma veya yineleyiciler kullanırsınız. Yineleyiciler kullanıyorsanız, kural aşağıdaki gibi kullanmak !=yerine kullanmaktır <:

for (auto it = foo.begin(); it != foo.end(); ++it) { ... }

Benzer şekilde, bir ağacı veya listeyi veya bir deque'yi yinelemek, genellikle bir dizinin aralık içinde kalıp kalmadığını kontrol etmek yerine boş bir işaretçi veya başka bir nöbetçi izlemeyi içerir.


3
Programlamada deyimin önemini vurgulamakta haklısınız. Bazı kodlara baktığımda ve tanıdık bir paterni varsa, kalıbı çıkaran zaman kaybetmem gerekmiyor, ancak doğrudan çekirdeğe gidebiliyor. Sanırım bu benim Yoda karşılaştırmaları ile ana tutuşum - deyimsel görünmüyorlar, bu yüzden ne demek istediklerini kastettiklerinden emin olmak için onları iki kez okumak zorunda kalıyorum.
Toby Speight

7

Bu yapıyı kullanmamanın bir nedeni kayan nokta sayılarıdır. !=sayılar aynı görünse bile nadiren doğru olarak değerlendireceğinden şamandıralarla kullanım için çok tehlikeli bir karşılaştırmadır. <veya >bu riski ortadan kaldırır.


Döngü yineleyiciniz bir kayan nokta sayısı ise, !=karşı <olanı sorunlarınızın en azıdır.
Lundin

7

Bu uygulamayı takip etmenin, her ikisinin de bir programlama dilinin, her şeyden önce, insanlar tarafından (diğerlerinin yanı sıra) okuyacağı bir dil olması ile ilgili iki ilişkili nedeni vardır.

(1) Biraz fazlalık. Doğal dilde, genellikle bir hata düzeltme kodu gibi, kesinlikle gerekli olandan daha fazla bilgi sağlıyoruz. Burada ekstra bilgi döngü değişkeni olduğunu i(burada fazlalık nasıl kullandığımı görmek? Eğer 'döngü değişkeni' ne anlama geldiğini bilmiyorsanız, ya da değişkenin adını unuttuysanız, "döngü değişkeni i" okuduktan sonra tam bilgi) döngü sırasında 5'ten azdır, sadece 5'ten farklı değildir. Yedeklilik okunabilirliği artırır.

(2) Sözleşme. Diller, belirli durumları ifade etmenin özel standart yollarına sahiptir. Belirlenen bir şeyi söylemenin yolunu izlemezseniz, yine de anlaşılacaksınız, ancak mesajınızın alıcısı için çaba daha büyük çünkü belirli optimizasyonlar işe yaramayacak. Misal:

Sıcak püre etrafında konuşma. Sadece zorluğu aydınlat!

İlk cümle bir Alman deyiminin tam bir çevirisi. İkincisi, ana sözcüklerin eşanlamlılarla değiştirildiği ortak bir İngilizce deyimdir. Sonuç anlaşılabilir ancak anlaşılması çok daha uzun sürüyor:

Çalıların etrafında dövmeyin. Sadece sorunu açıklayın!

Bu, ilk versiyonda kullanılan eşanlamlıların duruma İngilizce deyimdeki geleneksel sözcüklerden daha iyi uyması durumunda bile geçerlidir. Programcılar kodu okuduğunda da benzer kuvvetler geçerlidir. Bu yüzden de 5 != ive 5 > ikoyma garip yolları vardır sürece bunu daha normal takas standart olduğu bir ortamda çalışıyorsanız i != 5ve i < 5bu yolla. Muhtemelen tutarlılık 5 == idoğal ama hata eğilimli yerine yazmayı hatırlamayı kolaylaştırdığı için bu tür lehçe toplulukları vardır i == 5.


1
Ausgezeichnet . Benzer şekilde, test i < 17+(36/-3)şu şekilde yazılmaz (bunlar başka bir yerde kullanılan sabitler olsa bile; netlik için isimlerini yazmalısınız !).
usr2564301

6

Bu gibi durumlarda ilişkisel karşılaştırmaları kullanmak, her şeyden daha popüler bir alışkanlıktır. Yineleyici kategorileri ve karşılaştırılabilirlikleri gibi kavramsal düşüncelerin yüksek öncelik olarak kabul edilmediği zamanlarda popülerliğini geri kazandı.

Eşitlik karşılaştırmaları karşılaştırılan değerlere daha az gereksinim getirdiğinden, mümkün olduğunda ilişkisel karşılaştırmalar yerine eşitlik karşılaştırmaları kullanmayı tercih etmeliyim. Being EqualityComparable olmaktan daha az gerekliliktir LessThanComparable .

Bu bağlamlarda eşitlik karşılaştırmasının daha geniş uygulanabilirliğini gösteren bir başka örnek, unsignedyinelemenin uygulanmasına kadar olan popüler muammadır 0. Olarak yapılabilir

for (unsigned i = 42; i != -1; --i)
  ...

İlişkisel sürüm imzasız türlerle ayrılırken, yukarıdakilerin hem imzalı hem de imzasız yineleme için eşit olarak uygulanabilir olduğuna dikkat edin.


2

Döngü değişkeninin vücut içinde (kasıtsız) değişeceği örneklerin yanı sıra, operatörlerden daha küçük veya daha büyük operatörleri kullanmak için başka nedenler de vardır:

  • Olumsuzlukları kodun anlaşılmasını zorlaştırır
  • <veya >sadece bir karakter, ancak !=iki

4
İkinci mermi en iyi ihtimalle anlamsız bir nedendir. Kod doğru ve açık olmalıdır. Kompakt çok daha az önemlidir.
Jonathan Leffler

@JonathanLeffler Bir TDD REPL'de, bu ekstra karakter ayrıştırma için fazladan bir nano-saniye ve yazımın neden olduğu hatayı bulmak için milyarlarca kez yinelendi 5 != $i, bu da hayatımın bir saniyesini aldı. Uh ... snicker
piskopos

1

Riski azalttığını belirten çeşitli kişilere ek olarak, çeşitli standart kütüphane bileşenleriyle etkileşime geçmek için gereken işlev aşırı yüklerinin sayısını da azaltır. Örneğin, türünüzün a'da depolanmasını std::setveya std::maparama ve sıralama algoritmalarının bazıları için bir anahtar olarak kullanılmasını veya bazı anahtarlamalarla birlikte kullanılmasını istiyorsanız , standart kütüphane genellikle std::lessçoğu algoritmanın yalnızca katı bir zayıf sıralamaya ihtiyaç duyması nedeniyle nesneleri karşılaştırmak için kullanır . Böylece karşılaştırmalar (elbette mantıklı olduğu yerde) <yerine karşılaştırmaları kullanmak iyi bir alışkanlık haline gelir !=.


1
aşırı yüklerin sayısı konusunda doğru olabilirsiniz, ancak nesnelerdeki gereksinimleri göz önünde bulundurursanız, hemen hemen her nesne için bir !=operatör tanımlayabilir , ancak sıkı bir zayıf sipariş tanımlamak her zaman mümkün değildir. Bu anlamda !=daha iyi olurdu, çünkü tipe daha az gereksinim getiriyor. Ancak, hala kalmak <.
idclev 463035818

0

Sözdizimi açısından hiçbir sorun yoktur, ancak bu ifadenin arkasındaki mantık 5!=isağlam değildir.

Bence, !=for döngüsünün sınırlarını ayarlamak için mantıksal olarak ses gelmiyor çünkü for döngüsü yineleme dizinini artırıyor veya azaltıyor, bu nedenle yineleme dizini sınırların dışına (bir !=şeye) dönüşene kadar döngüyü ayarlamak bir doğru uygulama.

Bu çalışacaktır ancak kullanılırken sınır veri işleme kaybolur çünkü doğması eğilimli !=bir artan bir sorun için (eğer baştan biliyor yani eğer artar veya azalır) yerine, nedeni kullanılmaktadır.!=<>>==>


2
Mantık gayet iyi. Ne zaman ibir 5döngüden çıkılır. Başka bir şey mi demek istediniz?
Dan Getz

1
Veriler ısı nedeniyle doğru şekilde aktarılmazsa, elektromanyetik kodunuzun sonsuza kadar çalışmasını etkiler. Bunu ECC RAM'li normal bir iş istasyonunda veya sunucuda yaparsanız sorun yoktur (ne mantıksal, teknik ne de fiziksel)
Markus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.