Pratik olarak sonsuz gibi görünen bir 'for' döngüsü


82

Şu anda bazı kodlarda hata ayıklama yapıyorum ve şu satırla karşılaştım:

for (std::size_t j = M; j <= M; --j)

(Tatilde olan patronum tarafından yazılmıştır.)

Bana gerçekten tuhaf görünüyor.

Bu ne işe yarıyor? Bana göre sonsuz bir döngü gibi görünüyor.


31
size_tişaretsiz olduğundan, sıfırı kullanımdan kaldırmaya çalışırken döngüyü sonlandırırken maksimum değerine sarılması garanti edilir. Yine de korkunç kod.
BoBTFish

4
@Bathsheba Bunun Mmaksimum değeri olursa ne olur size_t? Hâlâ zeki olduğunu düşünüyor musun?
Thorsten Dittmar

8
@Barmar pek gelmiyor, Asla gelmiyor , yani bir olasılık var> 0. Bu da demek oluyor ki, çözümü basitleştirmenin yolları varken aptalca.
Thorsten Dittmar

38
Olumsuz oylamayı anlamıyorum. Bu soru açık - nasıl geliştirilebileceğini göremiyorum. Yeni bir kullanıcıdan, bu soru aslında ilginç !
Bathsheba

17
#define TRUE FALSEve tatile çıkın.
Leo

Yanıtlar:


68

std::size_tbir unsignedtür olması C ++ standardı tarafından garanti edilmektedir . Ve bir unsignedtürü 0'dan düşürürseniz , standart, bunu yapmanın sonucunun o tür için en büyük değer olduğunu garanti eder.

Çevreleyen bu değer her zaman 1'den büyük veya M1'e eşittir, böylece döngü sona erer.

Bu nedenle j <= M, bir unsignedtüre uygulandığında "döngüyü sıfıra kadar çalıştır ve sonra durdur" demenin uygun bir yoludur.

jİstediğinizden daha büyük bir tane çalıştırmak ve hatta slayt operatörünü kullanmak gibi alternatifler for (std::size_t j = M + 1; j --> 0; ){mevcuttur, bunlar muhtemelen daha nettir, ancak daha fazla yazma gerektirir. Sanırım bir dezavantajı (ilk incelemede ürettiği şaşırtıcı etkiden başka), Java gibi işaretsiz türlerin olmadığı dillere iyi uyum sağlamamasıdır.

Ayrıca, patronunuzun seçtiği planın, unsignedkümeden olası bir değeri "ödünç aldığını" unutmayın : Bu durumda, olarak Mayarlanmış olması std::numeric_limits<std::size_t>::max()doğru davranışa sahip olmayacaktır. Aslında bu durumda döngü sonsuzdur . (Gözlemlediğiniz şey bu mu?) Koda bu etkiyle ilgili bir yorum eklemeniz ve hatta muhtemelen bu belirli koşul üzerinde iddiada bulunmanız gerekir.


1 tabi Molmamak std::numeric_limits<std::size_t>::max().


7
Havayı suçluyorum.
Hatted Rooster

3
M ise std::numeric_limits<std::size_t>::max()o zaman M + 1sıfır olacak ve for (std::size_t j = M + 1; j --> 0; )döngü hiç döngüye girmez.
Pete Kirkham

51
Buna "slayt operatörü" deme. C ++ 'da böyle bir operatör yoktur, sadece zekice görünen bir şaşırtmacadır.
Sen

26
@DimitarMirchev: Çünkü bir operatör değil. Tek aralıklı iki operatör. Görüşülen kişilere alakasız sorular sormakta ısrar ediyorsanız buna bir deyim diyebilirsiniz (ama ideal olarak, onlara "akıllı" sözdizimi hakkında soru sormak yerine işlevselliği nasıl uygulayacaklarını sorun).
Sen

1
size_t64 bit olduğunu varsayarsak , uç durumda yanlış davranışı gözlemlemek birkaç yüz yıl sürecektir. (İyileştiricinin döngüden kurtulabilmesi dışında.)
Carsten S

27

Patronunuzun muhtemelen yapmaya çalıştığıM şey dahil olmak üzere sıfırdan geriye doğru saymak ve her sayı için bazı işlemler yapmaktı .

Ne yazık ki, bunun size gerçekten sonsuz bir döngü vereceği, sahip olabileceğiniz Mmaksimum size_tdeğerin olduğu bir uç durum var. Ve, işaretsiz bir değerin onu sıfırdan düşürdüğünüzde ne yapacağı iyi tanımlanmış olsa da, kodun kendisinin özensiz bir düşünce örneği olduğunu düşünüyorum, özellikle de patronlarınızın girişimlerinin eksiklikleri olmadan mükemmel bir şekilde uygulanabilir bir çözüm olduğu için.

Bu daha güvenli değişken (ve benim görüşüme göre, yine de sıkı bir kapsam sınırını korurken daha okunabilir olan) şöyle olacaktır:

{
    std::size_t j = M;
    do {
        doSomethingWith(j);
    } while (j-- != 0);
}

Örnek olarak, aşağıdaki koda bakın:

#include <iostream>
#include <cstdint>
#include <climits>
int main (void) {
    uint32_t quant = 0;
    unsigned short us = USHRT_MAX;
    std::cout << "Starting at " << us;
    do {
        quant++;
    } while (us-- != 0);
    std::cout << ", we would loop " << quant << " times.\n";
    return 0;
}

Bu, temelde bir ile aynı şeyi yapar unsigned shortve her bir değeri işlediğini görebilirsiniz :

Starting at 65535, we would loop 65536 times.

do..whileYukarıdaki koddaki döngüyü patronunuzun temelde yaptığı şeyle değiştirmek sonsuz bir döngü ile sonuçlanacaktır. Deneyin ve görün:

for (unsigned int us2 = us; us2 <= us; --us2) {
    quant++;
}

7
Şimdi, uç durum 0. Neden olmasın for(size_t j = M; j-- != 0; )?
LogicStuff

Evet, bu, köşe davasının belki de daha sık olmasından dolayı acı çekiyor numeric_limits<size_t>::max().
Bathsheba

7
@Logic ve diğerleri, sağladığım yöntemde uç durum yok, bunu göstermek için kod ekledim. Daki ile önerilen bir çözüm, bir başlangıç değerinin M == 0bu şekilde işlemden geçirilen elemanının 0 olmadığında neden olur yapar bir kenar durum var. Sonradan kontrol do..whileyöntemimi kullanmak , uç durumu tamamen ortadan kaldırır. Bunu birlikte çalışırsanız M == 1, bunu her ikisi 1'i yapar göreceksiniz ve bunu başlatmak Benzer 0'a max_size_t(olması umulur ki ne olursa olsun) ve başarıyla o noktada başlar sıfır dahil ve aşağı azaltacaktır.
paxdiablo

İlginç bir şekilde bu durum, bazılarının "yapılandırılmış kod değil" dediği şeyin kullanılmasını motive ediyor çünkü bir " exitif" kullanıyor { j =M; for(;;){ f(j); if( j == 0 )break; j -= 1; } }. Hatta C'nin adlandırılmış döngüleri olmadığı için, şeyler iç içe geçerse break, a ile değiştirilmesi gerekebilir goto. "Yapılandırılmış", "parçalar hakkında akıl yürütmeye duyarlı" anlamına geliyorsa, yapılandırılmıştır (düzen yardımcı olur!) Ve ayrıca "ön ve son koşullar hakkında akıl yürütme yoluyla resmi doğrulamaya duyarlı" anlamına geliyorsa. Bu durumda j--işe yarasa da, daha karmaşık bir geçiş gerektiğinde exitif stil haklı çıkarılabilir.
PJTraill

@PJTraill Söylediklerinizin yapılandırılmış olduğunu ve söylediklerinizin yapılandırılmadığını söyleyemiyorum. Do-while ile ilgili mantık yürütmek basittir. Bir çıkışı, while-do'dan daha fazla veya yapılandırılmamış bir şekilde "kullanmaz".
philipxy
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.