Tek satırlı if veya döngü için kaşlı ayraçlar (yani {}) kullanmanın amacı nedir?


321

C ++ öğretim elemanımın bazı ders notlarını okuyorum ve şunları yazdı:

  1. Girintiyi Kullan // Tamam
  2. Asla operatör önceliğine güvenmeyin - Her zaman parantez kullanın // Tamam
  3. Her zaman bir {} bloğu kullanın - tek bir satır için bile // tamam değil , neden ???
  4. Karşılaştırmanın sol tarafındaki sabit nesne // Tamam
  5. > = 0 // güzel hile olan değişkenler için imzasız kullanın
  6. Silme işleminden sonra İşaretçiyi NULL olarak ayarlayın - Çift silme koruması // kötü değil

3. teknik benim için net değil: Bir satırı bir a yerleştirerek ne kazanırdım { ... }?

Örneğin, şu garip kodu alın:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

ve aşağıdakilerle değiştirin:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;

1. sürümü kullanmanın yararı nedir?


256
Okunabilirlik ve bakım kolaylığı. 'J ++' ifadesinin hangi ifade bloğuna ait olduğu ve bundan sonra kod eklemenin if ifadesiyle ilişkili olmayacağı hemen belli değildir.
Orman ve Ağaçlar

27
Bana her zaman birkaç nedenden dolayı bu çizgiler için {} kıvırcık parantezlerini kullanmam söylendi. Kodun okunmasını kolaylaştırır. Ayrıca altı ay içinde başka birinin kodunuzu düzenlemesi gerekebilir, böylece netlik önemlidir ve parantezlerle bir hatanın oluşması daha az olasıdır. Teknik olarak daha doğru bir şey yok, daha iyi bir uygulama meselesi. Bir projenin, yeni bir adamın peşinden gitmesi için binlerce ve binlerce satır kodu olabileceğini unutmayın!
RossC

30
6 ile aynı fikirde değilim, çünkü bir çift silme ve potansiyel olarak mantık hatalarını gizleyecektir.
Luchian Grigore

28
5. zor olabilir - bu döngü düşünün: for (unsigned i = 100; i >= 0; --i).
Archie

36
Btw, (i % 2 == 0)çelişkiler (2). Operatör önceliğine güveniyorsunuz ve anlamı elbette ((i % 2) == 0)değil (i % (2 == 0)). Kural 2'yi "geçerli bir duygu" olarak sınıflandırırdım ama "her zaman" yanlıştır ".
Steve Jessop

Yanıtlar:


509

En de değiştirmeye çalışmayın edelim ibiz artırır zaman j:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
        i++;

Oh hayır! Python'dan geliyor, bu iyi görünüyor, ama aslında, buna eşdeğer olduğu için değil:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;

Tabii ki, bu aptalca bir hatadır, ancak deneyimli bir programcının bile yapabileceği bir hatadır.

Başka çok iyi bir nedeni de işaret edilmektedir ta.speot.is cevabı .

Aklıma gelen üçüncü bir şey iç içe geçmiş if:

if (cond1)
   if (cond2) 
      doSomething();

Şimdi, karşılanmadığı doSomethingElse()zaman istediğinizi varsayalım cond1(yeni özellik). Yani:

if (cond1)
   if (cond2) 
      doSomething();
else
   doSomethingElse();

elseiç ile olan ilişkiden beri yanlıştır if.


Düzenleme: Bu biraz dikkat çekiyor, benim görüşüme açıklık getireceğim. Yanıtladığım soru:

1. sürümü kullanmanın yararı nedir?

Hangi tarif ettiğim. Bazı faydaları var. Ancak IMO, "her zaman" kuralları her zaman geçerli değildir. Bu yüzden tamamen desteklemiyorum

Her zaman bir {} bloğu kullanın - tek bir satır için bile // tamam değil, neden ???

Her zaman bir {}blok kullan demiyorum . Yeterince basit bir durum ve davranış ise, yapmayın. Birisinin daha sonra girebileceğinden şüpheleniyorsanız ve kodunuzu işlevsellik eklemek için değiştirirseniz yapın.


5
@Science_Fiction: Doğru, ancak daha i++ önce eklerseniz j++, her iki değişken de kullanıldıklarında yine de kapsamda olacaktır.
Mike Seymour

26
Bu çok makul görünüyor, ancak editörün siz değil, girintiyi yaptığı gerçeğini ihmal ediyor ve i++;hemen döngünün bir parçası olmadığını gösteren bir şekilde girintili olacak . (Geçmişte, bu makul bir argüman olabilirdi ve böyle sorunlar gördüm. Yaklaşık 20 yıl önce. O zamandan beri değil.)
James Kanze

43
@James: Bu bir "gerçek" değil, iş akışınız. Ve birçok insanın iş akışı, ama herkesin değil. Ben öyle düşünmüyorum mutlaka tedavi C'ye bir hata ++ bir düz metin dosyası olarak kaynak yerine onu yürütmelidir Biçimlendirme kurallarını o bir WYSIWYG editörü (vi / emacs / Visual Studio) çıktısı. Yani bu kural, ihtiyacınız olanın ötesinde editörden bağımsızdır, ancak insanların C ++ 'ı düzenlemek için kullandıklarının ötesinde değildir. Dolayısıyla "savunmacı".
Steve Jessop

31
@JamesKanze Herkesin her zaman güçlü IDE'lerde çalıştığı varsayımına gerçekten güveniyor musunuz? En son yazılan CI Nano'daydı. Buna rağmen, bir IDE'de kapatma eğiliminde olduğum ilk şeylerden biri otomatik girintidir - çünkü IDE benim yoluma girme eğilimindedir , eksik bilgilere dayanarak 'hatalarımı' düzeltmeye çalışarak doğrusal olmayan iş . IDE'ler her programcının doğal akışını otomatik olarak girintilemede pek iyi değildir. Bu özellikleri kullanan programcılar tarzlarını IDE'leriyle birleştirme eğilimindedir, bu da sadece bir IDE kullanırsanız iyi olur, ancak birçoğunda çalışıyorsanız bile değil.
Rushyo

10
“Bu aptalca bir hatadır, ancak deneyimli bir programcının bile yapabileceği bir hatadır.” - Cevabımda söylediğim gibi, buna inanmıyorum. Bence bu gerçekte bir sorun teşkil etmeyen, tamamen yapışık bir dava.
Konrad Rudolph

324

{Ve kullanmıyorsanız kontrol akışını yanlışlıkla yorumlarla değiştirmek çok kolaydır }. Örneğin:

if (condition)
  do_something();
else
  do_something_else();

must_always_do_this();

Eğer dışarı yorum yaparsanız do_something_else()tek bir satır yorum ile, bu ile bitireceğiz:

if (condition)
  do_something();
else
  //do_something_else();

must_always_do_this();

Derlenir, ancak must_always_do_this()her zaman çağrılmaz.

Kod tabanımızda bu sorunu yaşadık, birileri yayınlanmadan önce bazı işlevleri çok hızlı bir şekilde devre dışı bırakmak için gitti. Neyse ki kod incelemesinde yakaladık.


3
Ohh oğlum !! must_always_do_this();yorum yaptığınızda tanımlanmış davranıştır // do_something_else ();
Anubis

1
@Supr, ilk yazıldığı gibi, parantez kullanırsanız doğru akışı kırmanın zor olduğunu söylüyor ve daha sonra kod düzgün bir şekilde parantez olmadan kırılmanın ne kadar kolay olduğunun bir örneğini veriyor
SeanC

20
Geçen gün bununla karşılaştım. if(debug) \n //print(info);. Temelde bir kütüphane çıkardı.
Kevin

4
Fortunately we caught it in code review.Ah! Kulağa yanlış geliyor. Fortunately we caught it in unit tests.çok daha iyi olurdu!
BЈовић

4
@ BЈовић Peki ya kod bir birim testindeyse? Zihin şaşkına döner. (Şaka yapıyorum, bu eski bir uygulama. Birim testleri yok.)
ta.speot.is 4:12

59

Öğretim elemanının yeterliliği konusunda şüphelerim var. Puanlarını göz önünde bulundurarak:

  1. tamam
  2. Herkes gerçekten yazar mı (veya okumak ister) (b*b) - ((4*a)*c) ? Bazı öncelikler açıktır (veya olması gerekir) ve ekstra parantezler sadece karışıklığa katkıda bulunur. (Öte yandan, gerekli olmadıklarını bilseniz bile, parantezleri daha az belirgin durumlarda kullanırsınız.)
  3. Bir çeşit. Koşulları ve döngüleri biçimlendirmek için iki geniş yayılma kuralı vardır:
    eğer (koşullu) {
        kod;
    }
    
    ve:
    eğer (koşul)
    {
        kod;
    }
    
    İlkinde ona katılırdım. Açıklık {o kadar görünür değil, bu yüzden her zaman orada olduğunu varsaymak en iyisidir. Ancak ikincisinde, ben (ve birlikte çalıştığım insanların çoğu), parantezleri tek bir ifadeye dahil etmede sorun yaşamıyor. (Tabii ki, girintinin sistematik olması ve bu stili sürekli olarak kullanmanız şartıyla. (Ve çok iyi programcılar, çok okunabilir kod yazarak, ilk yolu biçimlendirirken bile parantezleri atlarlar.)
  4. HAYIR . Gibi şeyler if ( NULL == ptr )okunabilirliği engelleyecek kadar çirkin. Karşılaştırmaları sezgisel olarak yazın. (Bu çoğu durumda sağdaki sabit ile sonuçlanır.) Onun 4'ü kötü tavsiye; kodu doğal olmayan yapan her şey onu daha az okunabilir yapar.
  5. HAYIR . Her şey olabilir ama intözel durumlar için ayrılmıştır. Deneyimli C ve C ++ programcılarına unsignedsinyal bit operatörlerinin kullanımı. C ++ gerçek bir kardinal tipine (veya başka bir etkili subrange tipine) sahip değildir; unsignedpromosyon kuralları nedeniyle sayısal değerler için çalışmaz. Seri numaraları gibi, hiçbir aritmetik işlemin anlamlı olmayacağı sayısal değerler tahmin edilebilir unsigned. Ancak buna karşı çıkarım çünkü yanlış mesaj gönderir: bitsel işlemler de mantıklı değil. Temel kural, integral türlerinin int, _unless_ başka bir tür kullanmanın önemli bir nedeni olmasıdır.
  6. HAYIR . Bunu sistematik olarak yapmak yanıltıcıdır ve aslında hiçbir şeye karşı koruma sağlamaz. Sıkı OO kodunda, delete this;(ve ayarlayamıyor genellikle en sık olduğu thisiçin NULL) ve aksi takdirde çoğu deletedaha sonra yine işaretçi erişemez böylece, yıkıcılar içindedir. Ve bunu ayarlamak, NULLetrafta yüzen diğer işaretçiler hakkında hiçbir şey yapmaz. İşaretçiyi sistematik olarak ayarlamak NULLyanlış bir güvenlik hissi verir ve size hiçbir şey satın almaz.

Tipik referansların herhangi birindeki koda bakın. Stroustrup, örneğin birincisi dışında verdiğiniz her kuralı ihlal ediyor.

Başka bir öğretim üyesi bulmanızı öneririm. Neden bahsettiğini gerçekten bilen biri.


13
4 sayısı çirkin olabilir, ancak bunun bir amacı vardır. Bunu önlemeye çalışıyor (ptr = NULL). Hiç kullandığımı sanmıyorum delete this, gördüğümden daha yaygın mı? Kullanımdan sonra bir işaretçi NULL için ayarlamak için yapmak bir şey kötü ama YMMV olduğunu düşünmek eğiliminde değilim. Belki de sadece benim ama rehberlerinin çoğu o kadar da kötü görünmüyor.
Firedragon

16
@Firedragon: Çoğu derleyici, if (ptr = NULL)siz yazmadığınız sürece uyarır if ((ptr = NULL)). James Kanze ile NULLilk olmanın çirkinliğinin benim için kesin bir HAYIR olduğunu kabul etmeliyim .
Leo

34
@JamesKanze: Burada belirttiğiniz şeylerin çoğuna katılmadığımı söylemeliyim - ancak onlara ulaştığınız için aldığınız argümanları takdir edip saygı duyuyorum. Deneyimli C ve C ++ programcılarına, imzasız sinyaller bit operatörlerinin kullanımı. - Hiç katılmıyorum: Bit operatörlerinin kullanımı, bit operatörlerinin kullanımını işaret eder. Bana göre, programlayıcının değişkenin yalnızca pozitif sayıları temsil etmesi gerektiği yönündeki istekliliğiniunsigned gösterir . İşaretli numaralarla karıştırmak genellikle derleyici uyarısına neden olur, bu da muhtemelen öğretim elemanının niyetinde olan şeydir.
Bileşen 10

18
Deneyimli C ve C ++ programcılarına, imzasız sinyallerin bit operatörlerinin kullanımı Ya da değil. size_t, kimse?
ta.speot.is

16
@ James Kanze, amacını düşün. Deneyimli bir programcı tarafından üretilen kodu öğretim örnekleriyle karşılaştırıyorsunuz. Bu kurallar öğretim elemanı tarafından sağlanır, çünkü öğrencilerinin gördüğü hatalardır. Deneyim ile, öğrenciler bu mutlakları rahatlatabilir veya göz ardı edebilir.
Joshua Shane Liberman

46

Diğer tüm cevaplar öğretim elemanınızın kuralını savunur 3.

Size katıldığımı söyleyeyim: kural gereksiz ve bunu tavsiye etmem. Her zaman kıvırcık parantez eklerseniz teorik olarak hataları önlediği doğrudur . Öte yandan, gerçek hayatta bu problemle hiç karşılaşmadım : diğer cevapların ima ettiği aksine, bir kez gerekli olduklarında kıvırcık parantezleri eklemeyi unutmadım. Doğru girinti kullanırsanız, birden fazla ifade girintilendikten sonra süslü parantez eklemeniz gerektiği hemen anlaşılır.

“Bileşen 10” un cevabı aslında bunun gerçekten bir hataya yol açabileceği akla gelebilecek tek durumu vurgulamaktadır. Ancak öte yandan, kodun düzenli ifadeyle değiştirilmesi her zaman büyük bir özen gerektirir.

Şimdi madalyanın diğer tarafına bakalım: her zaman kıvırcık parantez kullanmanın bir dezavantajı var mı? Diğer cevaplar bu noktayı görmezden geliyor. Ama olan bir dezavantaj: dikey ekran çok yer kaplıyor ve bu size gerekenden daha fazla kaydırmak zorunda anlamına gelir çünkü bu da sizin kod okunamaz yapabilirsiniz.

Başlangıçta çok sayıda güvenlik yan tümcesine sahip bir işlevi düşünün (ve evet, aşağıdaki kötü C ++ kodu ancak diğer dillerde bu oldukça yaygın bir durum olacaktır):

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
    {
        throw null_ptr_error("a");
    }
    if (b == nullptr)
    {
        throw null_ptr_error("b");
    }
    if (a == b)
    {
        throw logic_error("Cannot do method on identical objects");
    }
    if (not a->precondition_met())
    {
        throw logic_error("Precondition for a not met");
    }

    a->do_something_with(b);
}

Bu korkunç bir kod ve aşağıdakilerin büyük ölçüde daha okunabilir olduğunu şiddetle savunuyorum:

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
        throw null_ptr_error("a");
    if (b == nullptr)
        throw null_ptr_error("b");
    if (a == b)
        throw logic_error("Cannot do method on identical objects");
    if (not a->precondition_met())
        throw logic_error("Precondition for a not met");

    a->do_something_with(b);
}

Benzer şekilde, kısa iç içe döngüler kıvırcık parantezleri atlamaktan faydalanır:

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
        for (auto j = 0; j < a.h(); ++j)
            c(i, j) = a(i, j) + b(i, j);

    return c;
}

İle karşılaştırmak:

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
    {
        for (auto j = 0; j < a.h(); ++j)
        {
            c(i, j) = a(i, j) + b(i, j);
        }
    }

    return c;
}

İlk kod özlüdür; ikinci kod şişirilir.

Ve evet, bu , açılış çizgisini bir önceki hatta koyarak bir dereceye kadar hafifletilebilir . Ama bu olurdu hala herhangi kıvırcık parantez olmadan kod daha az okunabilir.

Kısacası: ekran alanı kaplayan gereksiz kod yazmayın.


26
Gereksiz yere ekran alanı kaplayan kod yazma inanmıyorsanız , açılış ayracı kendi satırına koyarak hiçbir işiniz yok . Muhtemelen şimdi GNU'nun kutsal intikamından kaçmak ve koşmak zorunda kalacağım, ama cidden - ya kodunuzun dikey olarak kompakt olmasını istersiniz ya da yapmazsınız. Ve eğer yaparsanız, kodunuzu daha az dikey olarak kompakt hale getirmek için tasarlanmış şeyleri yapmayın. Ama dediğin gibi, bunu düzelttikten sonra, artık parantezleri de kaldırmak isteyeceksin. Ya da sadece if (a == nullptr) { throw null_ptr_error("a"); }bir satır olarak yaz.
Steve Jessop

6
@Steve Nitekim olarak, do sen belirtilen sebeple, önceki satırda açılış ayracı koydu. Buradaki diğer stili, farkın ne kadar aşırı olabileceğini daha açık hale getirmek için kullandım.
Konrad Rudolph

9
+1 İlk örneğinizin diş telleri olmadan okunmasının çok daha kolay olduğunu tamamen kabul ediyorum. İkinci örnekte, kişisel kodlama tarzım, iç kısımda değil, dış for-loop'ta parantez kullanmaktır. @SteveJessop ile dikey veya kompakt kod hakkında aşırı veya diğeri olmak zorunda değilim. Dikey alanı azaltmak için tek astarlı ekstra parantezleri atlıyorum, ancak açılış parantezlerimi yeni bir çizgiye koydum çünkü parantezler sıralandığında kapsamı görmeyi daha kolay buluyorum. Amaç okunabilirliktir ve bazen bu daha fazla dikey alan kullanmak anlamına gelir, diğer zamanlarda daha az kullanmak demektir.
Travesti3

22
"Bu problemle gerçek hayatta hiç karşılaşmadım": şanslısın. Bunun gibi şeyler sadece sizi yakmaz,% 90 üçüncü derece yanıklar verir (ve akşam geç saatlerde bir düzeltme talep eden birkaç yönetim katmanı).
Richard

9
@Richard Bunu satın almıyorum. Sohbette açıkladığım gibi, bu hata hiç oluşmasa bile (ki bu pek olası değildir) yığın izine baktığınızda düzeltmek önemsizdir, çünkü hatanın sadece koda bakarak olduğu açıktır. Abartılı iddianız tamamen temelsizdir.
Konrad Rudolph

40

Üzerinde çalıştığım kod temeli, parantezlere patolojik bir nefreti olan insanlar tarafından kodla dağılmış ve daha sonra gelen insanlar için, sürdürülebilirlik açısından gerçekten bir fark yaratabilir.

Karşılaştığım en sık karşılaşılan sorunlu örnek şudur:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
    this_looks_like_a_then-statement_but_isn't;

Bu yüzden gelip o zaman bir ifade eklemek istediğimde, dikkatli olmazsam bununla kolayca sonuçlanabilirim:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
{
    this_looks_like_a_then-statement_but_isn't;
    i_want_this_to_be_a_then-statement_but_it's_not;
}

O neden hiç olur, ayıklama birkaç karıştı dakika ~ sürer 1 saniyede parantez eklemek ve en azından seni kurtarabilecek göz önüne alındığında değil azaltılmış belirsizlik seçeneği ile gitmek? Bana sahte ekonomi gibi geliyor.


16
Bu örnekteki sorun, diş telleri yerine yanlış girinti ve çok uzun satırlarda değil mi?
Honza Brabec

7
Evet, ancak insanların 'çok uzun satırlara sahip olmamaları gibi' başka yönergeleri de takip ettiklerini varsayarak sadece 'güvenli' olan tasarım / kodlama yönergelerini izlemek sorun istemektedir. Diş telleri en başından itibaren olsaydı, bu durumda yanlış bir if-bloğu ile sonuçlanmak imkansız olurdu.
reçel

16
Diş telleri nasıl eklenir ( if(really long...editor){ do_foo;}bu durumdan kaçınmanıza yardımcı olur mu? Sorun hala aynı olacak gibi görünüyor. koddaki fazladan iki satırdan dolayı
Grizzly

1
İyi bir nokta - Parantez kullanımını zorlamanın da mantıklı bir yere yerleştirilmesiyle sonuçlanacağını varsayıyordum, ancak elbette işleri zorlaştırmaya kararlı biri, örneğinizde olduğu gibi onları sıraya koyabiliyordu. Yine de çoğu insanın düşünmeyeceğini düşünürdüm.
reçel

2
Bir dosyaya dokunduğum ilk ve son şey otomatik format düğmesine basmak. Bu sorunların çoğunu ortadan kaldırır.
Jonathan Allen

20

Benim 2c:

Girinti Kullan

belli ki

Asla operatör önceliğine güvenmeyin - Her zaman parantez kullanın

"Asla ve" her zaman "kelimeleri kullanmazdım, ama genel olarak bu kuralın yararlı olduğunu görüyorum.Bazı dillerde (Lisp, Smalltalk) bu bir sorun değil.

Her zaman bir {} bloğu kullanın - tek bir satır için bile

Bunu asla yapmadım ve hiçbir zaman tek bir sorunum olmadı, ama bunun öğrenciler için nasıl iyi olabileceğini görebiliyorum, özellikle. daha önce Python okuduysa.

Karşılaştırmanın sol tarafındaki sabit nesne

Yoda koşulları? Hayır lütfen. Okunabilirliği incitir. Kodunuzu derlerken maksimum uyarı seviyesini kullanmanız yeterlidir.

> = 0 olan değişkenler için imzasız kullanın

TAMAM. Çok komik, Stroustrup'un aynı fikirde olmadığını duydum.

Silme işleminden sonra İşaretçiyi NULL olarak ayarlayın - Çift silme koruması

Kötü tavsiye! Asla silinmiş veya var olmayan bir nesneyi gösteren bir işaretçi kullanmayın.


5
Sadece son nokta için +1. İşlenmemiş bir işaretçinin zaten belleğe sahip bir işi yok.
Konrad Rudolph

2
İmzasız kullanım konusunda: sadece Stroustrup değil, K&R (C cinsinden), Herb Sutter ve (sanırım) Scott Meyers. Aslında, C ++ kurallarını gerçekten anlayan hiç kimsenin imzasız olduğunu iddia ettiğini duymadım.
James Kanze

2
@JamesKanze Aslında Stroustrup'un (2008'de bir Boston konferansı) fikrini duydum, Herb Sutter oradaydı ve yerinde Bjarne ile aynı fikirde değildi.
Nemanja Trifunovic

3
Sadece " unsignedkırık" tamamlamak için , sorunlardan biri C ++ benzer boyutlu imzalı ve imzasız türleri karşılaştırdığınızda, karşılaştırma yapmadan önce imzasız olanı dönüştürür olmasıdır . Bu da değer değişikliğine neden olur. İmzalı olana dönüştürmek çok daha iyi olmazdı; her iki değer de her iki türdeki tüm değerleri temsil edebilecek daha büyük bir türe dönüştürülmüş gibi "karşılaştırma" gerçekleşmelidir.
James Kanze

1
@SteveJessop Geri dönen bir işlev bağlamında almanız gerektiğini düşünüyorum unsigned. Eminim :-) exp(double)daha fazla bir değer döndürme ile hiçbir sorunu yoktur MAX_INT. Ama bir kez daha, asıl sorun örtük dönüşümlerdir. int i = exp( 1e6 );tamamen geçerli C ++. Stroustrup, aslında bir noktada kayıplı örtülü dönüşümleri reddetmeyi önerdi, ancak komite ilgilenmedi. (İlginç bir soru: olur unsigned-> intkayıplı düşünülebilir ben de ele alacak. unsigned-> intve int-> unsignedkayıplı hale getirmek için uzun bir yol gider hangisi. unsignedOK
James Kanze

18

daha sezgisel ve kolay anlaşılır. Niyeti açıklığa kavuşturuyor.

Ve bu yeni bir kullanıcı bilmeden kaçırabilir, kodun sonu yok olmasını sağlar {, }yeni bir kod deyimi eklerken.


Makes the intent clear+1, bu muhtemelen en özlü ve doğru nedendir.
Qix - MONICA

13

Yukarıdaki çok mantıklı önerilere eklemek için, bunun kritik hale geldiği bazı kodları yeniden düzenlerken karşılaştığım bir örnek şöyleydi: Bir API'den diğerine geçmek için çok büyük bir kod tabanını değiştiriyordum. İlk API, Şirket Kimliğini aşağıdaki gibi ayarlamak için bir çağrı yaptı:

setCompIds( const std::string& compId, const std::string& compSubId );

oysa ikame iki görüşmeye ihtiyaç duydu:

setCompId( const std::string& compId );
setCompSubId( const std::string& compSubId );

Bunu çok başarılı olan düzenli ifadeler kullanarak değiştirmeye başladım. Kodu astyle de geçtik , bu da gerçekten çok daha okunabilir hale getirdi. Sonra, gözden geçirme süreci boyunca kısmen, bazı koşullu durumlarda bunu değiştirdiğini keşfettim:

if ( condition )
   setCompIds( compId, compSubId );

Buna:

if ( condition )
   setCompId( compId );
setCompSubId( compSubId );

ki bu açıkça gerekli olan şey değil. Ben tamamen bir blok içinde yerine muamele ve daha sonra goofy seyir sona eren bir şey el ile değiştirerek tekrar yapmak zorunda kaldı (en azından yanlış olmaz.)

Fark ettim Astyle'nin artık --add-bracketshiçbiri olmayan köşeli parantez eklemenize izin veren bir seçeneğe sahip ve kendinizi olduğu gibi aynı konumda bulursanız bunu şiddetle tavsiye ederim.


5
Bir zamanlar harika para "Microsoftligent" olan bazı belgeleri gördüm. Evet, global arama ve değiştirme ile önemli hatalar yapmak mümkündür. Bu, yalnızca küresel arama ve değiştirme işleminin mikro yumuşakça değil akıllıca kullanılması gerektiği anlamına gelir.
Pete Becker

4
Bunun benim post-mortem'im olmadığını biliyorum, ancak kaynak kodda metin değiştirme yapacaksanız, bunu iyi kurulmuş metin değiştirme türü için kullanacağınız kurallara göre yapmalısınız. dilde: makrolar. Bir makro #define FOO() func1(); \ func2(); yazmamalısınız (ters eğik çizgiden sonra satır sonu ile), aynı arama ve değiştirme için de geçerlidir. Bununla birlikte, bir stil kuralı olarak "her zaman parantez kullan" ı tam olarak gördüm, çünkü tüm çoklu ifadeli makrolarınızı sarmanızı önler do .. while(0). Ama katılmıyorum.
Steve Jessop

2
Btw, bu Japon knotweed'in iyi kurulmuş olduğu anlamıyla "iyi kurulmuş": Makroları ve metin değiştirmeyi kullanma yolumuzdan çıkmamız gerektiğini söylemiyorum, ama böyle bir şey yaptığımızda şey, sadece belirli bir stil kuralı tüm kod tabanına başarıyla uygulandığında işe yarayan bir şey yapmak yerine, işe yarayacak bir şekilde yapmalıyız :-)
Steve Jessop

1
@SteveJessop Biri parantez ve kemer için de tartışabilir. Bu tür makroları kullanmanız gerekiyorsa (ve C ++ ve öncesinde yaptık inline), muhtemelen gerektiğinde do { ... } while(0)hile (ve çok fazla parantez kullanarak) olabildiğince çok bir işlev gibi çalışmayı hedeflemelisiniz . Seni her yerde parantez kullanmanı engellemiyorum, eğer ev tarzı bu ise. (FWIW: Burada tartışılan tüm stilleri kapsayan, farklı ev stilleri olan yerlerde çalıştım. Ciddi bir sorun olarak hiç bulamadım.)
James Kanze

1
Ve sanırım, ne kadar çok stille çalışıyorsanız kodu o kadar dikkatli okuyup düzenlersiniz. Bu yüzden, okunması en kolay olanı tercih etseniz bile, diğerlerini de başarıyla okuyacaksınız. Farklı ekipler tarafından farklı bileşenlerin farklı "ev tarzlarında" yazıldığı bir şirkette çalıştım ve doğru çözüm, küresel bir stil yaratmaya çalışmak değil, büyük bir etkiye sahip öğle yemeğinde şikayet etmektir :-)
Steve Jessop

8

{}Açık olduğu birkaç durum dışında her yerde kullanıyorum . Tek satır durumlardan biridir:

if(condition) return; // OK

if(condition) // 
   return;    // and this is not a one-liner 

Geri dönmeden önce bir yöntem eklediğinizde size zarar verebilir. Girinti, koşul karşılandığında dönüşün yürütüldüğünü gösterir, ancak her zaman dönecektir.

C # ifadesini kullanarak diğer örnek

using (D d = new D())  // OK
using (C c = new C(d))
{
    c.UseLimitedResource();
}

eşdeğer

using (D d = new D())
{
    using (C c = new C(d))
    {
        c.UseLimitedResource();
    }
}

1
Sadece usingifadede virgül kullanın ve zorunda değilsiniz :)
Ry-

1
@minitech Bu basitçe burada işe yaramıyor - virgül yalnızca eşit olduğunda, eşit olmayan türler için değil. Lukas'ın bunu yapma şekli kanonik yöntemdir, IDE bunu farklı şekilde biçimlendirir (ikincisinin otomatik girintisinin eksikliğine dikkat edin using).
Konrad Rudolph

8

Düşünebileceğim en uygun örnek:

if(someCondition)
   if(someOtherCondition)
      DoSomething();
else
   DoSomethingElse();

Hangi ifolacak elseeşleşmiş olmalıdır? Girinti dış ima ifalır else, ama bu derleyici bunu görecek kadar aslında değil; İç if alacak elseve dışif buna gerek yoktur. Bu kodun neden beklentilerinizi karşılayamayacağını denetleyerek bunu anlamanız gerektiğini bilmelisiniz (veya hata ayıklama modunda bu şekilde davrandığını görmelisiniz). Python'u tanıyorsanız daha kafa karıştırıcı olur; bu durumda girintinin kod bloklarını tanımladığını bilirsiniz, böylece girintiye göre değerlendirmesini beklersiniz. Ancak, C # boşluk hakkında uçan bir flip vermez.

Şimdi, bu "yüzünde her zaman parantez kullanın" kuralına özellikle katılmıyorum dedi. Kodu çok dikey olarak gürültülü hale getirir ve hızlı bir şekilde okuma yeteneğini azaltır. İfade şu ise:

if(someCondition)
   DoSomething();

... o zaman böyle yazılmalıdır. "Her zaman parantez kullan" ifadesi, "her zaman matematiksel işlemleri parantez içine al" gibi sesler çıkarır. Bu, çok basit bir ifadeyi , yakın bir paren (bir kodlayıcının bane'si) kaçırma olasılığını a * b + c / dgetirecek ((a * b) + (c / d))ve ne için? İşlem sırası iyi bilinir ve iyi uygulanır, bu nedenle parantezler gereksizdir. Parantezleri yalnızca normalde uygulanmasından farklı bir işlem sırası uygulamak için kullanırsınız: a * (b+c) / dörneğin. Blok parantezler benzerdir; bunları varsayılandan farklı olduğu ve "açık" olmadığı (öznel, ancak genellikle sağduyu) durumlarda ne yapmak istediğinizi tanımlamak için kullanın.


3
@AlexBrown ... bu tam olarak benim açımdan. OP'de belirtilen kural, belirttiğim sebeple aynı fikirde olmadığım "her zaman tek satırlar için bile parantez kullanın" dır. Parantezler ediyorum kod girintili var kaba davranışını çünkü, ilk kod örneği ile yardımcı; Eşleştirmek parantez kullanmak zorunda kalacak elseilk ile ifyerine ikinci. Lütfen aşağı oyu kaldırın.
KeithS

5

Cevaplara baktığımızda, hiç kimse alışkanlık yaptığım türden bir alışkanlığı açıkça belirtmedi ve kodunuzun hikayesini anlattı:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

Oluyor:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0) j++;
}

Eğer if ile aynı satırj++ üzerine koyarak kimseye işaret etmelidir, "Ben sadece bu bloğun artmasını istiyorum " . Coursethis itibariyle burada bir kesme noktası koyarak çünkü hattı, mümkün olduğunca basit olarak ise sadece değerli olduğunu peri bahseder, çok faydalı olacak değildir.j

Aslında ben sadece java bu tür 'kod' olan Twitter fırtına API parçası üzerinde çalıştım, İşte bu slayt gösterisi sayfa 43 , relipant snippet yürütme kodu formu :

...
Integer Count = counts.get(word);
if (Count=null) count=0;
count++
...

For döngü bloğu içinde iki şey var, bu yüzden bu kodu satır içi olmaz. Yani asla :

int j = 0;
for (int i = 0 ; i < 100 ; ++i) if (i % 2 == 0) j++;

Korkunç ve işe yarayıp yaramadığını bile bilmiyorum; bunu yapma . Yeni çizgiler ve kaşlı ayraçlar, aynı şekilde virgül veya noktalı virgülün düzyazıda yaptığı gibi, ayrı ancak ilgili kod parçalarını ayırt etmeye yardımcı olur. Yukarıdaki blok, birkaç cümle ve ayrı kısımları ayırt etmek için asla kırılmayan veya duraklamayan diğer bazı ifadelerle çok uzun bir cümle kadar kötüdür.

Gerçekten başka birine telgraf yapmak istiyorsanız, üçlü bir operatör veya ?:form kullanan tek satırlık bir iştir :

for (int i = 0 ; i < 100 ; ++i) (i%2 ? 0 : >0) j++;

Ama bu kod-golf üzerinde verging olduğunu ve ben büyük bir uygulama sanmıyorum (j ++ koymak :ya da değil bir tarafa koymak gerekir açık değil). Not Daha önce C ++ üçlü bir işleç çalıştırmadım, bunun işe yarayıp yaramadığını bilmiyorum, ama var .

Kısacası:

Okuyucunuzun (kodu yöneten kişinin) hikayenizi (kod) nasıl yorumladığını düşünün. Onlar için olabildiğince netleştirin. Acemi kodlayıcının / öğrencinin bunu sürdürdüğünü biliyorsanız, belki de {}mümkün olduğunca çok şey bırakın , böylece kafaları karışmaz.


1
(1) İfadeyi aynı satıra koymak, daha az değil daha az okunabilir hale getirir . Özellikle bir artış gibi basit düşünceler kolayca gözden kaçabilir. Do yeni bir satırda koydu. (2) Tabii ki fordöngünüzü tek bir satıra koyabilirsiniz , neden bu işe yaramasın ki? Diş tellerini atlayabilmeniz için aynı nedenden dolayı çalışır; newline C ++ 'da önemli değildir. (3) Koşullu operatör örneğiniz, korkunç olmanın yanı sıra, geçersiz C ++.
Konrad Rudolph

@KonradRudolph teşekkürler, C ++ 'da biraz paslıyım. Asla (1) daha okunabilir olduğunu söylemedim, ama bu kod parçasının bir satır çevrimiçi olması gerektiği anlamına gelecektir. (2) Yorumum, onu okuyamayacağım ve işe yaradığını bilemediğimden daha fazlaydı, ne olursa olsun ya da istendiği gibi; bu nedenle ne yapmamaya bir örnek. (3) Teşekkürler, uzun zamandır C ++ yazmadım. Bunu şimdi düzeltirim.
Pureferret

2
Ayrıca bir satıra birden fazla ifade koymak, kodda hata ayıklamayı zorlaştırır. Bu çizgideki 2. ifadeye kırılma noktasını nasıl koyarsınız?
Piotr Perak

5

Çünkü iki ifadeniz olmadan {}, bir konuyu kaçırmak kolaydır. Kodun böyle göründüğünü varsayalım.

int error = 0;
enum hash_type hash = SHA256;
struct hash_value *hash_result = hash_allocate();

if ((err = prepare_hash(hash, &hash_result))) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &client_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &server_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &exchange_params)) != 0)
    goto fail;
    goto fail;
if ((err = hash_finish(hash)) != 0)
    goto fail;

error = do_important_stuff_with(hash);

fail:
hash_free(hash);
return error;

İyi görünüyor. Bununla ilgili sorunu, özellikle kodu içeren işlev çok daha büyük olduğunda kaçırmak gerçekten kolaydır. Mesele şudur ki goto fail, koşulsuz bir şekilde yürütülmüştür. Bunun ne kadar sinir bozucu olduğunu kolayca hayal edebilirsiniz ( hash_updateher şeyin hash_updateişlevinde iyi görünmesinden sonra sonun neden başarısız olduğunu sormanızı sağlar).

Ancak, bu {}her yere eklediğim anlamına gelmez (bence {}her yeri görmek sinir bozucu). Sorunlara neden olsa da, kişisel kodlama tarzım {}aynı hatta olmadıkları sürece koşulsuzları yasakladığından, kendi projelerim için hiçbir zaman olmadı (evet, kodlama tarzımın geleneksel olmadığını kabul ediyorum, ama hoşuma gidiyor ve ben diğer projelere katkıda bulunurken projenin kod stilini kullanın). Bu, aşağıdaki kodu iyi yapar.

if (something) goto fail;

Ama şu değil.

if (something)
    goto fail;

Kesinlikle. Sadece (tamamen gereksiz) yeni satır + girintisini koymayın ve bu sorunu herkesin gündeme getireceği kadar hızlı olduğu için tamamen kaldırıyorsunuz.
Alexander - Monica'yı

4

Döngülerinizin ve koşullu bloklarınızın kapsamını açıkça tanımlayarak kodunuzu daha okunabilir hale getirir. Ayrıca sizi yanlışlıkla yapılan hatalardan da korur.


4

wrt 6: Boş bir işaretçiyi silmek bir işlem olmadığı için daha güvenlidir. Bu nedenle, yanlışlıkla bu yoldan iki kez geçerseniz, bellek bozulmasının, boş olan veya başka bir şeye tahsis edilen belleği boşaltmasına neden olmazsınız.

Bu, yaşamları çok net olmayan ve yok edildikten sonra yeniden oluşturulduğu bilinen statik dosya kapsamı nesneleri ve tek tonları ile ilgili bir konudur.

Çoğu durumda, auto_ptrs kullanarak buna olan ihtiyacı önleyebilirsiniz


6
Bu yoldan iki kez geçerseniz bir programlama hatası ile karşılaşırsınız. Bu hatayı daha az zararlı hale getirmek için bir işaretçiyi null değerine ayarlamak altta yatan sorunu çözmez.
Pete Becker

1
Kabul ettim, ancak daha önce tavsiye edildiğini gördüm ve bunun bazı profesyonel programlama standartlarında olduğuna inanıyorum. Poster profesörünün neden iyi olduğu yerine neden ortaya çıktığı hakkında daha fazla yorum yapıyordum
Tom Tanner

2
Pete Becker'in söylediklerini takip ederek: altta yatan sorunu çözmez, ancak maskeleyebilir. (İşaretçiyi NULLsildikten sonra ayarlayacağınız durumlar vardır . NULLİşaretçinin bu koşullarda sahip olması için doğru bir değer varsa; örneğin işaretçi önbelleğe alınmış bir değeri NULLgösterir ve geçersiz bir önbellek gösterir. bir NULLyıkıcıda son satır olarak bir işaretçi , onun C ++ biliyor olup olmadığını merak ediyorsun.)
James Kanze

4

Luchian'ın kabul edilen cevabını seviyorum, aslında onun doğru yolunu öğrendim, bu yüzden tek satırlı bloklar için bile her zaman parantez kullanıyorum. Ancak, örneğinizde olduğu gibi, bir filtre yazarken şahsen bir istisna yapıyorum. Bu:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

bana dağınık görünüyor. Gerçekten döngü tek bir eylem olduğunda, for döngüsünü ve if ifadesini ayrı eylemlere ayırır: 2 ile bölünebilen tüm tam sayıları saymak. Daha anlamlı bir dilde, bu şöyle yazılabilir:

j = [1..100].filter(_%2 == 0).Count

Kapanışı olmayan dillerde, filtre tek bir ifadede ifade edilemez, ancak bir for döngüsü ve ardından bir if ifadesi olmalıdır. Ancak, hala programcının zihninde bir eylemdir ve bunun koda yansıtılması gerektiğine inanıyorum:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
  if (i % 2 == 0)
{
    j++;
}

7
Herkesin görmezden nasıl başardığını gibi for (int i = 0; i < 100; i += 2);girinti ilgili tartışmayı devam uğruna, ;-) "en iyi" "Her biri için mantığı ifade etmek nasıl olabilir bir bütün ayrı bunfight, muhtemelen var ibelli bir özelliği olan belli bir aralıkta" standart algoritmaların kabus kombinasyonunu kullanan bir döngü olmadan C ++ 'da filter_iteratorve / veya counting_iterator.
Steve Jessop

1
Ayrıca, buna sahip olsaydık, sonuçta ortaya çıkan muazzam tek ifadenin nasıl girintileneceğine katılmayabilirdik.
Steve Jessop

2
@Steve, bu sadece bir örnek. Desenin birçok meşru kullanımı vardır. Açıkçası, 2'ye bölünebilen 1'den 100'e kadar olan sayıları saymak istiyorsanız, yapmanız gereken tek şey 100/2'dir.
MikeFHay

2
Tabii, biliyorum, bu yüzden " ibelirli bir mülk ile belirli bir aralıktaki her biri için" soyutladım . Sadece SO'da insanlar, verilen örneğe tamamen farklı bir yaklaşım lehine asıl soruyu görmezden gelmek için çok hızlıdır. Ancak girintilemek önemlidir , bu yüzden yapmayız ;-)
Steve Jessop

4

Yukarıda açıklanan hataları önlemeye yardımcı olmak için bir seçenek, parantez kullanmadığınızda ne olmasını istediğinizi satır içine almaktır. Kodu değiştirmeye çalıştığınızda hataları fark etmemeyi çok daha zorlaştırır.

if (condition) doSomething();
else doSomethingElse();

if (condition) doSomething();
    doSomething2(); // Looks pretty obviously wrong
else // doSomethingElse(); also looks pretty obviously wrong

5
Çünkü İkinci seçenek, bir derleme hatası doğuracak elsebir ilişkili değildir if.
Luchian Grigore

Satır içi ile o kadar görünür olmayan bir sorun, varsayılan olarak çoğu IDE'nin otomatik format yardımcı programını kullanırken girintili stille değiştirmesidir.
Honza Brabec

@Honza: Bu oldukça yüklü bir siyasi mesele. Bir kod tabanı üzerinde işbirliği yapıyorsak, ya her girintili ayrıntıya kadar aynı girintileme stilini kullanmalıyız, ya da her ikisinin de mevcut kodu "sadece" olarak otomatik biçimlendirmemeyi kabul etmeliyiz. Birincisi, üzerinde anlaşılan stil yine de bunu içeriyorsa, ancak IDE'nizi buna uyacak şekilde yapılandırmanız veya otomatik format kullanmamanız gerekir. Hepimiz aynı IDE'yi sonsuza dek kullanırsak, aksi halde çok iyi değilse, ortak formatın "IDE'm otomatik biçimlendirdiği her ne olursa olsun" olduğunu kabul etmek çok iyidir.
Steve Jessop

3

Eğer bir derleyici iseniz, hiçbir fark yaratmaz. Her ikisi de aynı.

Ancak programcılar için birincisi daha açık, okunması kolay ve daha az hataya açıktır.


2
{Zaten kendi hattında açmanın dışında .
Rob

3

Kıvırcık parantez eklemeye başka bir örnek. Bir kez bir hata arıyordum ve böyle bir kod buldum:

void SomeSimpleEventHandler()
{
    SomeStatementAtTheBeginningNumber1;
    if (conditionX) SomeRegularStatement;
    SomeStatementAtTheBeginningNumber2;
    SomeStatementAtTheBeginningNumber3;
    if (!SomeConditionIsMet()) return;
    OtherwiseSomeAdditionalStatement1;
    OtherwiseSomeAdditionalStatement2;
    OtherwiseSomeAdditionalStatement3;
}

Yöntemi satır satır okursanız, yöntemde doğru değilse dönen bir koşul olduğunu fark edeceksiniz. Ama aslında bazı koşullara bağlı olarak bazı değişkenler ayarlayan 100 diğer basit olay işleyicisi gibi görünüyor. Ve bir gün Hızlı Kodlayıcı gelir ve yöntemin sonuna ek değişken ayarı ifadesi ekler:

{
    ...
    OtherwiseSomeAdditionalStatement3;
    SetAnotherVariableUnconditionnaly;
}

Sonuç olarak, SetAnotherVariableUnconditionnaly, SomeConditionIsMet () olduğunda yürütülür, ancak hızlı adam bunu fark etmedi çünkü tüm satırlar neredeyse benzer boyuttadır ve dönüş koşulu dikey olarak girintili olsa bile, o kadar da fark edilmez.

Koşullu getiri şu şekilde biçimlendirilirse:

if (!SomeConditionIsMet())
{
    return;
}

çok dikkat çekicidir ve Hızlı Kodlayıcı bir bakışta bulacaktır.


Hızlı kodlayıcınız, returnbir işlev eklemeden önce bir işlev gövdesi içinde sözdizimi vurgulanmış bir ifadeyi bulmak için rahatsız edilemezse, hızlı kodlayıcının kodunuza yaklaşmasına izin vermemelisiniz. Böyle bir adamın parantez ekleyerek kodunuzun etrafında gezinmesini engellemezsiniz.
cmaster

@cmaster Artık bizimle çalışmıyor. Her neyse, sözdizimi vurgulamak iyidir, ancak net bir şekilde görmeyen kişiler olduğunu unutmayın (geçen yıl kör bir programcıdan bir yazı bile gördüm).
Artemix

2

Birincisinin sonra net olduğunu düşünüyorum. Kapanma talimatı verir, kod karmaşıklaştığında küçük kod iyi {...}olur endifveya olmasa bile çok yardımcı olur.begin...end

//first
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}


//second
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;

1

İşiniz bittiğinde işaretçiyi NULL olarak ayarlamak en iyisidir.

İşte bir neden:

A sınıfı aşağıdakileri yapar:

  1. Bir bellek bloğu tahsis eder
  2. Sonra bir süre sonra, bu bellek bloğunu siler, ancak işaretçiyi NULL olarak ayarlamaz.

B Sınıfı aşağıdakileri yapar

  1. Belleği ayırır (ve bu örnekte A sınıfı tarafından silinen aynı bellek bloğuna sahip olur)

Bu noktada hem A Sınıfı hem de B Sınıfı, aynı bellek bloğuna işaret eden işaretçiler içerir, A Sınıfı söz konusu olduğunda, bu bellek bloğu, bittiği için mevcut değildir.

Aşağıdaki sorunu düşünün:

Sınıf A'da şimdi Sınıf B'ye ait olan belleğe yazılmasına neden olan bir mantık hatası varsa ne olur?

Bu özel durumda, bellek adresi yasal olduğu için kötü erişim özel durumu hatası almayacaksınız, ancak A sınıfı şimdi B sınıfı verilerini etkin bir şekilde bozuyor.

B Sınıfı, beklenmedik değerlerle karşılaşırsa çökebilir ve çökme olasılığı varsa, sorun A probleminde B sınıfında bu hatayı avlamak için oldukça uzun zaman harcayacaksınız.

Silinen bellek işaretçisini NULL olarak ayarlamış olsaydınız, A Sınıfındaki herhangi bir mantık hatası NULL işaretçisine yazmaya çalıştığında bir istisna hatası alırsınız.

İşaretçiler ikinci kez NULL olduğunda çift silme ile mantık hatası konusunda endişeleriniz varsa, bunun için onay ekleyin.

Ayrıca: Oyu düşürecekseniz, lütfen açıklayınız.


2
Bir mantık hatası varsa, maskelemek yerine düzeltilmelidir.
uınbɐɥs

@Barmar, OP diyor ... 6. Silme işleminden sonra İşaretçiyi NULL olarak ayarlayın - Korumayı çift sil // kötü değil. Bazı insanlar bunu Null olarak ayarlamamaya yanıt verdiler ve neden NULL olarak ayarlanması gerektiğini söylüyorum, 6'nın hangi kısmı 6. NULL ayarına cevabım 6'ya uymuyor?
John

1
@Shaquin, Peki bu mantık hatalarını ilk etapta nasıl bulmayı öneriyorsunuz? Bellek silindikten sonra işaretçi değişkenini NULL olarak ayarladıktan sonra. NULL işaretçisine başvurma girişimi, yasadışı girişiminizin yapıldığı satırdaki hata ayıklayıcıya kilitlenir. Geri dönüp mantık hatasının nerede olduğunu görebilir ve sorunu düzeltebilirsiniz. Belleği sildikten sonra işaretçi değişkenini NULL olarak ayarlamazsanız, UNAWARE mantık hataları nedeniyle bu silinen belleği yazma girişiminiz başarısız olabilir ve bu nedenle bu noktada çökmez. Maskeleme değil.
John

1

Her zaman kıvırcık parantezlere sahip olmak çok basit ve sağlam bir kuraldır. Ancak çok sayıda diş teli olduğunda kod yetersiz görünebilir. Kurallar kıvırcık parantezleri atlamaya izin veriyorsa, daha ayrıntılı stil kuralları ve daha sofistike araçlar olmalıdır. Aksi takdirde kaotik ve kafa karıştırıcı (zarif olmayan) kodlarla kolayca sonuçlanabilir. Bu nedenle, kullanılan stil kılavuzlarından ve araçlardan ayrı olarak tek stil kuralına bakmak muhtemelen sonuç vermez. Bu kural # 3 hakkında, diğer cevaplarda bile belirtilmemiş olan bazı önemli detayları getireceğim.

İlk ilginç detay, bu kuralın savunucularının çoğunun davayı ihlal ettiğini kabul etmesidir else. Başka bir deyişle, böyle bir kodun incelenmesini talep etmezler:

// pedantic rule #3
if ( command == Eat )
{
    eat();
}
else
{
    if ( command == Sleep )
    {
        sleep();
    }
    else
    {
        if ( command == Drink )
        {
            drink();
        }
        else
        {
            complain_about_unknown_command();
        }
    }
}

Bunun yerine, görürlerse böyle yazmayı önerebilirler:

// not fully conforming to rule #3
if ( command == Eat )
{
    eat();
}
else if ( command == Sleep )
{
    sleep();
}
else if ( command == Drink )
{
    drink();
}
else
{
   complain_about_unknown_command();
}

Hiçbir kıvırcık parantez arasında bulunmaktadır beri bu teknik olarak bu kuralın ihlali olduğunu elseveif . Kuralın böyle bir ikiliği, akılsız bir araçla otomatik olarak kod tabanına uygulanmaya çalışıldığında ortaya çıkar. Gerçekten, neden tartışmak için, bir aracın stili otomatik olarak uygulamasına izin verin.

İkinci ayrıntı (bu kuralın savunucuları tarafından da sıklıkla unutulur) oluşabilecek hataların asla sadece bu kuralın 3'ünün ihlali nedeniyle olmamasıdır. Aslında neredeyse her zaman # 1 kuralı ihlalleri içerir (kimsenin tartışamadığı). Yine otomatik araçlar açısından, # 1 kuralı ihlal edildiğinde hemen şikayet eden bir araç yapmak zor değildir ve bu nedenle hataların çoğu zamanında yakalanabilir.

Üçüncü ayrıntı (genellikle bu kuralın muhalifleri tarafından unutulur), tek noktalı virgülle temsil edilen boş ifadenin kafa karıştırıcı doğasıdır. Biraz tecrübesi olan çoğu geliştirici er ya da geç tek yanlış noktalı virgül ya da tek noktalı virgül kullanılarak yazılan boş deyim ile karıştı. Tek noktalı virgül yerine iki kıvrımlı parantezin görsel olarak fark edilmesi daha kolaydır.


1

Her zaman {}tek satır için kullanılmadığını itiraf etmeliyim , ancak bu iyi bir uygulama.

  • Diyelim ki köşeli parantezsiz şöyle bir kod yazıyorsunuz:

    için (int i = 0; i <100; ++ i) için (int j = 0; j <100; ++ j) DoSingleStuff ();

Ve bir süre sonra jbaşka şeyler eklemek istersiniz ve bunu hizalama ile yaparsınız ve parantez eklemeyi unutursunuz.

  • Bellek ayrılması daha hızlıdır. Diyelim ki büyük bir kapsamınız var ve içeride büyük diziler oluşturuyorsunuz new. Bu diziler, kapsamdan çıktıktan hemen sonra bellekten siliniyor. Ancak bu diziyi tek bir yerde kullanmanız ve bir süre yığın halinde olması ve bir çeşit çöp olması mümkündür. Bir istifin sınırlı ve oldukça küçük bir boyutu olduğundan, istif boyutunu aşmak mümkündür. Bu nedenle bazı durumlarda bundan {}kaçınmak için yazmak daha iyidir . NOT bu tek satır için değil, bu tür durumlar için:

    if (...) {// SomeStuff ... {// if, while, vb. yok. // SomeOtherStuff} // SomeMoreStuff}

  • Kullanmanın üçüncü yolu ikinciye benzer. Bu sadece yığın temiz hale getirme için değil açmak , bazı işlevler. mutexUzun işlevlerde kullanıyorsanız , verilere erişmeden hemen önce ve bunu okuduktan / yazdıktan hemen sonra kilitlemek ve kilidini açmak daha iyidir. NOT bazı kendi varsa bu şekilde kullanıyor classveya structbirlikte constructorve destructorkilit belleğine.

  • Dahası:

    if (...) if (...) SomeStuff (); başka SomeOtherStuff (); // eğer ikinciye gider, ama alligment önce olduğunu gösterir ...

Sonuçta, her zaman {}tek bir satır için kullanmanın en iyi yolu nedir diyemem ama bunu yapmak kötü bir şey değil.

ÖNEMLİ DÜZENLEME Tek bir satır için derleme kodu parantezleri yazdığınızda hiçbir şey yapmaz, ancak kodunuz yorumlanacaksa kodu çok yavaş yavaşlatır. Çok az.


1

Kontrol ifadeleri yazmanın birkaç olası yolu vardır; bunların bazı kombinasyonları okunabilirliği bozmadan birlikte bulunabilir, ancak diğer kombinasyonlar sorun yaratacaktır. Tarzı

if (condition)
  statement;

kontrol ifadeleri yazmanın diğer bazı yollarıyla rahatça birlikte var olacak, ancak diğerleriyle o kadar iyi olmayacak. Çok satırlı denetimli ifadeler şöyle yazılırsa:

if (condition)
{
  statement;
  statement;
}

hangi ififadelerin tek bir satırı ve hangilerinin birden fazla satırı kontrol ettiği görsel olarak açık olacaktır . Ancak, çok satırlı ififadeler şöyle yazılırsa:

if (condition) {
  statement;
  statement;
}

o zaman ifgerekli parantez eklemeden tek ifadeli yapıları genişletmeye çalışan birinin olasılığı çok daha yüksek olabilir.

ifKod tabanı formdan önemli ölçüde yararlanırsa, bir sonraki satırdaki tekli ifade de sorunlu olabilir.

if (condition) statement;

Kendi tercihim, ifadenin kendi satırında olması, ifbenzer kontrol bloklarına sahip birçok ifadenin olduğu durumlar dışında genellikle okunabilirliği arttırmasıdır;

if (x1 > xmax) x1 = xmax;
if (x1 < xmin) x1 = xmin;
if (x2 > xmax) x2 = xmax;
if (x2 < xmin) x2 = xmin;
etc.

bu durumda, genellikle ifdiğer kodlardan görsel olarak ayırmak için bu tür ifade gruplarından önce boş bir satırla devam edeceğim . Hepsi ifaynı girinti ile başlayan bir dizi ifadeye sahip olmak, olağandışı bir şey olduğuna dair net bir görsel gösterge sağlayacaktır.

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.