web-dev-qa-db-fra.com

Quel est le but d'utiliser des accolades (c'est-à-dire {}) pour une ligne unique if ou loop?

Je lis des notes de cours de mon conférencier C++ et il a écrit ce qui suit:

  1. Utiliser l'indentation // OK
  2. Ne comptez jamais sur la priorité de l'opérateur - Utilisez toujours des parenthèses // OK
  3. Toujours utiliser un bloc {} - même pour une seule ligne // pas OK, pourquoi ???
  4. Objet Const à gauche de la comparaison // OK
  5. Utilisez unsigned pour les variables> = 0 // Belle astuce
  6. Définissez le pointeur sur NULL après la suppression - Protection contre la suppression double // pas mal

La 3ème technique n’est pas claire pour moi: que gagnerais-je en plaçant une ligne dans un { ... }?

Par exemple, prenons ce code étrange:

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

et le remplacer par:

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

Quel est l'avantage d'utiliser la 1ère version?

312
JAN

Essayons également de modifier i lorsque nous incrémentons j:

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

Oh non! Venant de Python, ça a l'air correct, mais en fait ça ne l'est pas, ça équivaut à:

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

Bien sûr, c’est une erreur idiote, mais que même un programmeur expérimenté pourrait commettre.

Une autre très bonne raison est signalée dans réponse de ta.speot.is .

Un troisième auquel je peux penser est imbriqué if ':

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

Supposons maintenant que vous souhaitiez maintenant doSomethingElse() lorsque cond1 N'est pas atteint (nouvelle fonctionnalité). Alors:

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

ce qui est évidemment faux puisque le else s'associe au if intérieur.


Edit: Depuis cela attire un peu d'attention, je vais clarifier mon point de vue. La question à laquelle je répondais est:

Quel est l'avantage d'utiliser la 1ère version?

Ce que j'ai décrit Il y a quelques avantages. Mais, IMO, les règles "toujours" ne s'appliquent pas toujours. Donc je ne supporte pas totalement

Toujours utiliser un bloc {} - même pour une seule ligne // pas OK, pourquoi ???

Je ne dis pas toujours utilisez un bloc {}. Si c'est une condition et un comportement assez simples, ne le faites pas. Si vous pensez que quelqu'un pourrait arriver plus tard et changer votre code pour ajouter des fonctionnalités, faites-le.

505
Luchian Grigore

Il est très facile de changer accidentellement le contrôle-flux avec des commentaires si vous n'utilisez pas { Et }. Par exemple:

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

must_always_do_this();

Si vous commentez do_something_else() avec un commentaire d'une seule ligne, vous obtiendrez ceci:

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

must_always_do_this();

Il compile, mais must_always_do_this() n'est pas toujours appelé.

Nous avions ce problème dans notre base de code, où quelqu'un était venu désactiver certaines fonctionnalités très rapidement avant la publication. Heureusement, nous l'avons détecté lors de la révision du code.

318
ta.speot.is

J'ai des doutes quant à la compétence du conférencier. Considérant ses points:

  1. D'accord
  2. Quelqu'un voudrait-il vraiment écrire (ou vouloir lire) (b*b) - ((4*a)*c)? Certains précédents sont évidents (ou devraient l'être), et les parenthèses supplémentaires ne font qu'ajouter à la confusion. (D'autre part, vous devriez utiliser les parenthèses dans des cas moins évidents, même si vous savez qu'elles ne sont pas nécessaires.)
  3. Sorte de. Il existe deux conventions très répandues pour le formatage des conditionnelles et des boucles:
     if (cond) {
     code; 
    } 
    
    et:
     if (cond) 
     {
     code; 
    } 
    
    Dans la première, je suis d’accord avec lui. L'ouverture { N'est pas visible, il est donc préférable de supposer que c'est toujours là. Dans le second cas, cependant, moi-même (et la plupart des personnes avec qui j'ai travaillé) n'avons aucun problème à omettre les accolades pour une seule déclaration. (À condition, bien sûr, que l'indentation soit systématique et que vous utilisiez ce style de manière cohérente. (Et beaucoup de très bons programmeurs, écrivant du code très lisible, omettent les accolades même lors du formatage initial.)
  4. NON. Des choses comme if ( NULL == ptr ) sont assez laides pour nuire à la lisibilité. Écrivez les comparaisons intuitivement. (Ce qui entraîne souvent la constante à droite.) Son 4 est un mauvais conseil. tout ce qui rend le code non naturel le rend moins lisible.
  5. NON. Tout sauf int est réservé à des cas particuliers. Pour les programmeurs C et C++ expérimentés, l’utilisation de unsigned signale aux opérateurs de bits. C++ n'a pas de type cardinal réel (ni aucun autre type de sous-gamme efficace); unsigned ne fonctionne pas pour les valeurs numériques, à cause des règles de promotion. Les valeurs numériques sur lesquelles aucune opération arithmétique n’aurait de sens, comme les numéros de série, pourraient vraisemblablement être unsigned. Je suis contre, cependant, parce que cela envoie un mauvais message: les opérations au niveau des bits n’ont pas de sens non plus. La règle de base est que les types intégraux sont int, il existe une raison importante d'utiliser un autre type.
  6. NON. Faire systématiquement cela est trompeur et ne protège en réalité contre rien. Dans strict OO code, delete this; Est souvent le cas le plus fréquent (et vous ne pouvez pas définir this sur NULL.), Et sinon , la plupart des delete se trouvent dans des destructeurs, vous ne pouvez donc pas accéder au pointeur ultérieurement. De plus, le régler sur NULL ne fait rien à propos des autres pointeurs flottants. NULL donne un faux sentiment de sécurité et ne vous achète pas vraiment.

Regardez le code dans l'une des références typiques. Stroustrup enfreint toutes les règles que vous avez données, à l'exception de la première, par exemple.

Je suggérerais que vous trouviez un autre conférencier. Celui qui sait réellement de quoi il parle.

60
James Kanze

Toutes les autres réponses défendent la règle de votre conférencier 3.

Permettez-moi de dire que je suis d’accord avec vous: la règle est redondante et je ne le conseillerais pas. Il est vrai que théoriquement évite les erreurs si vous ajoutez toujours des accolades. D’autre part, je n’ai jamais rencontré ce problème dans la vie réelle: contrairement à ce que d’autres réponses impliquent, je n’ai pas oublié une seule fois d’ajouter les accolades une fois que cela est devenu nécessaire. Si vous utilisez l'indentation appropriée, il devient immédiatement évident que vous devez ajouter des accolades une fois que plusieurs instructions sont indentées.

La réponse de "Composant 10" met en évidence le seul cas concevable où cela pourrait réellement conduire à une erreur. Par contre, remplacer le code par une expression régulière nécessite toujours un soin considérable.

Voyons maintenant de l’autre côté de la médaille: existe-t-il un inconvénient consistant à toujours utiliser des accolades? Les autres réponses ignorent simplement ce point. Mais il y a un inconvénient: cela prend beaucoup d'espace à l'écran, ce qui peut rendre votre code illisible car cela signifie que vous devez faire défiler plus que nécessaire.

Considérons une fonction avec beaucoup de clauses de garde au début (et oui, ce qui suit est un mauvais code C++, mais dans d'autres langages, ce serait une situation assez courante):

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

C’est un code horrible, et j’argue fortement que ce qui suit est beaucoup plus lisible:

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

De même, les boucles imbriquées courtes tirent avantage de l’omission des accolades:

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

Comparer avec:

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 premier code est concis; le deuxième code est gonflé.

Et oui, cela peut être atténué dans une certaine mesure en plaçant l'accolade ouvrante sur la ligne précédente. Mais cela serait quand même moins lisible que le code sans accolades.

En bref: n’écrivez pas de code inutile qui prend de la place à l’écran.

46
Konrad Rudolph

La base de code sur laquelle je travaille est parsemée de code par des personnes ayant une aversion pathologique pour les accolades, et pour les personnes qui se présentent plus tard, cela peut réellement améliorer la maintenabilité.

L'exemple problématique le plus fréquent que j'ai rencontré est le suivant:

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;

Donc, quand je viens et que je souhaite ajouter une déclaration alors, je peux facilement me retrouver avec ceci si je ne fais pas attention:

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

Étant donné qu'il faut environ 1 seconde pour ajouter des accolades et que vous pouvez économiser au moins quelques minutes de débogage confuses, pourquoi voudriez-vous jamais pas opter pour l'option d'ambiguïté réduite? Cela me semble une fausse économie.

39
jam

Mon 2c:

Utiliser l'indentation

Évidemment

Ne comptez jamais sur la priorité de l'opérateur - Utilisez toujours des parenthèses

Je n'utiliserais pas les mots "jamais et" toujours ", mais en général, cette règle me paraît utile. Dans certaines langues (LISP, Smalltalk), il ne s'agit pas d'un problème.

Toujours utiliser un bloc {} - même pour une seule ligne

Je ne fais jamais cela et n'ai jamais eu un seul problème, mais je peux voir à quel point cela peut être bon pour les étudiants, en particulier. si ils ont étudié Python avant.

Objet Const à gauche de la comparaison

Yoda conditions? Non je t'en prie. Cela fait mal la lisibilité. Utilisez simplement le niveau d'avertissement maximum lorsque vous compilez votre code.

Utilisez unsigned pour les variables> = 0

D'ACCORD. Assez drôle, j'ai entendu Stroustrup en désaccord.

Définissez le pointeur sur NULL après la suppression - Protection contre la double suppression

Mauvais conseil! Ne jamais avoir un pointeur qui pointe vers un objet supprimé ou non existant.

19
Nemanja Trifunovic

c'est plus intuitif et facilement compréhensible. Cela rend l'intention claire.

Et cela garantit que le code ne casse pas lorsqu'un nouvel utilisateur risque de rater inconsciemment le {, } en ajoutant une nouvelle instruction de code.

17
Alok Save

Pour ajouter aux suggestions très judicieuses ci-dessus, un exemple que j’ai rencontré lors de la refactorisation de certains codes critiques est le suivant: j’étais en train de modifier une très grande base de code pour passer d’une API à une autre. La première API avait un appel pour définir l'ID de la société comme suit:

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

alors que le remplacement nécessitait deux appels:

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

J'ai décidé de changer cela à l'aide d'expressions régulières, ce qui a été un franc succès. Nous avons également passé le code par astyle , ce qui l'a rendu beaucoup plus lisible. Ensuite, à mi-chemin du processus de révision, j'ai découvert que dans certaines circonstances conditionnelles, cela changeait ceci:

if ( condition )
   setCompIds( compId, compSubId );

Pour ça:

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

ce qui n'est clairement pas ce qui était requis. Je devais revenir au début pour faire cela à nouveau en traitant le remplaçant comme complètement dans un bloc, puis en modifiant manuellement tout ce qui finissait par paraître maladroit (du moins, cela ne serait pas faux.)

Je remarque que astyle a maintenant l'option --add-brackets qui vous permet d’ajouter des crochets là où il n’y en a pas et je le recommande vivement si vous vous retrouvez dans la même situation que moi.

13
Component 10

L'exemple le plus pertinent auquel je puisse penser:

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

Avec quel if le else sera-t-il associé? L'indentation implique que if extérieur obtienne le else, mais ce n'est pas ainsi que le compilateur le verra; le innerif obtiendra le else, et le if extérieur ne le sera pas. Vous devez le savoir (ou le voir se comporter de cette manière en mode débogage) pour comprendre par inspection pourquoi ce code risque de ne pas répondre à vos attentes. Cela devient plus déroutant si vous connaissez Python; dans ce cas, vous savez que l'indentation définit des blocs de code, vous vous attendez donc à ce qu'il soit évalué en fonction de l'indentation. C #, cependant, ne donne pas une volée volante sur les espaces.

Cela dit, je ne suis pas particulièrement d'accord avec cette règle du "toujours utiliser les crochets". Cela rend le code très bruyant verticalement, réduisant la possibilité de le lire rapidement. Si la déclaration est:

if(someCondition)
   DoSomething();

... alors il devrait être écrit comme ça. La déclaration "toujours utiliser des crochets" sonne comme "toujours entourer les opérations mathématiques par des parenthèses". Cela transformerait la très simple déclaration a * b + c / d En ((a * b) + (c / d)), En introduisant la possibilité de manquer un proche (le fléau de beaucoup de codeurs), et pour quoi? L'ordre des opérations étant bien connu et bien appliqué, les parenthèses sont redondantes. Vous utiliseriez uniquement des parenthèses pour appliquer un ordre d'opérations différent de celui qui serait normalement appliqué: a * (b+c) / d par exemple. Les accolades de bloc sont semblables; utilisez-les pour définir ce que vous voulez faire dans les cas où il diffère de celui par défaut et n’est pas "évident" (subjectif, mais généralement assez logique).

8
KeithS

J'utilise {} _ partout sauf dans quelques cas où c'est évident. Une seule ligne est l'un des cas suivants:

if(condition) return; // OK

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

Cela peut vous blesser lorsque vous ajoutez une méthode avant le retour. L'indentation indique que le retour est en cours d'exécution lorsque la condition est remplie, mais il retourne toujours.

Autre exemple en C # avec using statment

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

ce qui équivaut à

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

En regardant à travers les réponses, personne ne dit explicitement le type de pratique que je prends d'habitude, racontant l'histoire de votre code:

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

Devient:

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

Mettre le j++ Sur le même ligne comme si le if devrait signaler à qui que ce soit, "Je veux seulement que ce bloc incrémente jamais j" . Bien sûr, cela n’est utile que si la ligne est aussi simpliste que possible, car placer un point de rupture ici, comme peri , ne sera pas très utile.

En fait, je viens de croiser une partie de l'API Twitter Storm qui propose ce type de code en Java. Voici l'extrait correspondant du code d'exécution, sur page 43 de ce diaporama :

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

Le bloc de boucle for contient deux éléments. Par conséquent, je ne mettrais pas ce code en ligne. Ie jamais :

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

C'est affreux et je ne sais même pas si cela fonctionne (comme prévu); ne faites pas ceci . Les nouvelles lignes et accolades permettent de distinguer les éléments de code distincts mais liés, de la même manière qu'une virgule ou un point-virgule le font en prose. Le bloc ci-dessus est aussi une très longue phrase avec quelques clauses et quelques autres déclarations qui ne se cassent jamais ni ne s'interrompent pour distinguer des parties séparées.

Si vous voulez vraiment télégraphier à quelqu'un d'autre, utilisez un opérateur ternaire ou ?: form:

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

Mais ceci est proche du code-golf, et je pense que ce n’est pas une bonne pratique (j’ignore si je devrais mettre le j ++ d’un côté du : Ou non). [~ # ~] nb [~ # ~] Je n'ai pas exécuté d'opérateur ternaire en C++ auparavant, je ne sais pas si cela fonctionne, mais ça existe.

En bref:

Imaginez comment votre lecteur (la personne qui gère le code) interprète votre histoire (code). Faites le aussi clairement que possible pour eux. Si vous savez que le codeur/étudiant novice le maintient, vous pouvez peut-être même laisser autant de {} Que possible, juste pour qu'ils ne s'embrouillent pas.

5
Pureferret

Parce que lorsque vous avez deux déclarations sans {}, Il est facile de rater un problème. Supposons que le code ressemble à ceci.

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;

Ça semble bien. Le problème avec cela est vraiment facile à manquer, surtout lorsque la fonction contenant le code est beaucoup plus grande. Le problème est que goto fail Est exécuté inconditionnellement. Vous pouvez facilement imaginer à quel point c'est frustrant (vous demandant pourquoi la dernière hash_update Échoue toujours, après tout, tout se passe bien dans la fonction hash_update).

Cependant, cela ne veut pas dire que je dois ajouter {} Partout (à mon avis, voir {} Partout est agaçant). Bien que cela puisse poser problème, cela ne s’est jamais produit pour mes propres projets, car mon style de codage personnel interdit les conditionnelles sans {} Quand elles ne sont pas sur la même ligne (oui, je conviens que mon style de codage est non conventionnel, mais Je l’aime bien, et j’utilise le style de code du projet pour contribuer à d’autres projets). Cela rend le code suivant très bien.

if (something) goto fail;

Mais pas le suivant.

if (something)
    goto fail;
5
Konrad Borowski

wrt 6: C'est plus sûr car la suppression d'un pointeur NULL est une opération impossible. Ainsi, si vous passez par ce chemin deux fois par inadvertance, vous ne causerez pas de corruption de mémoire, ce qui ne libérera pas de mémoire libre ou allouée à autre chose.

Ceci est principalement un problème avec les objets de portée de fichier statique et les singletons qui n'ont pas une durée de vie très claire et qui sont connus pour être recréés après leur destruction.

Dans la plupart des cas, vous pouvez éviter ce problème en utilisant auto_ptrs.

4
Tom Tanner

L'une des options permettant d'éviter les erreurs décrites ci-dessus consiste à indiquer ce que vous voulez faire lorsque vous n'utilisez pas d'accolades. Il est beaucoup plus difficile de ne pas remarquer les erreurs lorsque vous essayez de modifier le code.

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

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

J'aime la réponse acceptée de Luchian. En fait, j'ai appris à la dure qu'il avait raison. J'utilise donc toujours des accolades, même pour les blocs d'une ligne. Cependant, personnellement, je fais une exception lors de l'écriture d'un filtre, comme dans votre exemple. Cette:

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

semble encombré pour moi. Il sépare les boucles for et l'instruction if en actions distinctes, alors que votre intention est une action unique: compter tous les entiers divisibles par 2. Dans un langage plus expressif, ceci pourrait être écrit de la manière suivante:

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

Dans les langues dépourvues de fermetures, le filtre ne peut pas être exprimé dans une instruction unique, mais doit être une boucle for suivie d'une instruction if. Cependant, cela reste une action dans l’esprit du programmeur, et j’estime que cela devrait être reflété dans le code, comme suit:

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

Cela rend votre code plus lisible en définissant clairement la portée de vos boucles et de vos blocs conditionnels. Cela vous évite également des erreurs accidentelles.

4
Drona

Un autre exemple d'ajout d'accolades. Une fois, je cherchais un bogue et trouvais un tel code:

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

Si vous lisez la méthode ligne par ligne, vous remarquerez qu'une condition de la méthode est renvoyée si elle n'est pas vraie. Mais en réalité, cela ressemble à 100 autres gestionnaires d’événements simples qui définissent certaines variables en fonction de certaines conditions. Et un jour, le codeur rapide intervient et ajoute une instruction de réglage variable supplémentaire à la fin de la méthode:

{
    ...
    OtherwiseSomeAdditionalStatement3;
    SetAnotherVariableUnconditionnaly;
}

Par conséquent, SetAnotherVariableUnconditionnaly est exécuté lorsque SomeConditionIsMet (), mais le fast guy ne l’a pas remarqué car toutes les lignes ont une taille presque similaire et même lorsque la condition de retour est indentée verticalement, elle n’est pas aussi visible.

Si le retour conditionnel est formaté comme ceci:

if (!SomeConditionIsMet())
{
    return;
}

c'est très visible et le Fast Coder le trouvera en un coup d'œil.

3
Artemix

Si vous êtes un compilateur, cela ne fait aucune différence. Les deux sont les mêmes.

Mais pour les programmeurs, le premier est plus clair, facile à lire et moins sujet aux erreurs.

3
P.P.

Je considère que le premier est clair, puis le second. Cela donne l'impression de fermer les instructions, avec peu de code, c'est bien quand le code devient complexe {...} aide beaucoup même si c'est endif ou 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++;
2
RollRoll

Je dois admettre que pas toujours utiliser {} pour une seule ligne, mais c'est une bonne pratique.

  • Disons que vous écrivez un code sans crochets qui ressemble à ceci:

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

Et après un certain temps, vous voulez ajouter dans j une boucle, et vous ne le faites que par alignement sans oublier d’ajouter des crochets.

  • La distribution de la mémoire est plus rapide. Disons que vous avez une grande portée et créez de grands tableaux à l'intérieur (sans new alors ils sont empilés). Ces tableaux sont supprimés de la mémoire juste après que vous ayez quitté la portée. Mais il est possible que vous utilisiez ce tableau à un endroit et qu'il soit en pile pendant un certain temps et soit une sorte de foutaise. Comme une pile a une taille limitée et assez petite, il est possible de dépasser la taille de la pile. Donc, dans certains cas, il vaut mieux écrire {} pour éviter cela. NOTE ce n'est pas pour une seule ligne mais pour une telle situation:

    if (...) {// SomeStuff ... {// nous n'avons pas de if, while, etc. // SomeOtherStuff} // SomeMoreStuff}

  • La troisième façon de l'utiliser est semblable à la deuxième. Ce n'est pas juste pour rendre la pile plus propre, mais pour ouvrir certaines fonctions. Si vous utilisez mutex dans des fonctions longues, il est généralement préférable de verrouiller et de déverrouiller juste avant d'accéder aux données et juste après la fin de la lecture/écriture. NOTE cette méthode est utilisée si vous avez vos propres class ou struct avec constructor et destructor pour verrouiller la mémoire.

  • De plus:

    si (...) si (...) SomeStuff (); else SomeOtherStuff (); // va à la seconde si, mais alligment montre que c'est en premier ...

Je ne saurais dire quelle est la meilleure façon de toujours utiliser {} pour une seule ligne, mais il n’ya rien de mal à le faire.

IMPORTANT EDIT Si vous écrivez des accolades de code de compilation pour une seule ligne ne fait rien, mais si votre code doit être interprété, cela ralentira très légèrement le code. Très légèrement.

1
ST3

Toujours avoir des accolades est une règle très simple et robuste. Cependant, le code peut sembler inélégant quand il y a beaucoup d'accolades. Si les règles permettent d'omettre les accolades, il devrait y avoir des règles de style plus détaillées et des outils plus sophistiqués. Sinon, il peut en résulter facilement un code chaotique et déroutant (pas élégant). Par conséquent, rechercher une règle de style unique distincte du reste des guides de style et des outils utilisés est probablement infructueux. J'apporterai simplement quelques détails importants sur cette règle n ° 3 qui n'ont même pas été mentionnés dans d'autres réponses.

Le premier détail intéressant est que la plupart des partisans de cette règle acceptent de la violer dans le cas de else. En d'autres termes, ils n'exigent pas en revue ce code:

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

Au lieu de cela, s'ils le voient, ils peuvent même suggérer de l'écrire comme ça:

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

C'est techniquement une violation de cette règle puisqu'il n'y a pas d'accolades entre else et if. Une telle dualité de la règle apparaît lorsque l’on essaie de l’appliquer automatiquement à la base de code avec un outil stupide. En effet, pourquoi argumenter, il suffit de laisser un outil pour appliquer le style automatiquement.

Le deuxième détail (souvent oublié par les partisans de cette règle) est que les erreurs qui peuvent survenir ne sont jamais dues à des violations de cette règle n ° 3. En fait, ceux-ci impliquent presque toujours des violations de la règle n ° 1 également (personne ne discute avec). Toujours du point de vue des outils automatiques, il n’est pas difficile de créer un outil qui se plaint immédiatement lorsque la règle n ° 1 est enfreinte, de sorte que la plupart des erreurs puissent être détectées à temps.

Le troisième détail (souvent oublié par les opposants à cette règle) est la nature confuse d’une déclaration vide représentée par un simple point-virgule. La plupart des développeurs ayant une certaine expérience ont été tôt ou tard confondus avec un simple point-virgule égaré ou une instruction vide écrite avec un seul point-virgule. Deux accolades au lieu d'un seul point-virgule sont visuellement plus faciles à repérer.

1
Öö Tiib

Il est préférable de définir le pointeur sur NULL lorsque vous avez terminé.

Voici un exemple pourquoi:

La classe A fait ce qui suit:

  1. Alloue un bloc de mémoire
  2. Puis quelque temps plus tard, il supprime ce bloc de mémoire mais ne positionne pas le pointeur sur NULL

La classe B fait ce qui suit

  1. Alloue de la mémoire (et dans ce cas, le même bloc de mémoire a été supprimé par la classe A.)

À ce stade, les classes A et B ont des pointeurs pointant sur le même bloc de mémoire. En ce qui concerne la classe A, ce bloc de mémoire n’existe pas car il est terminé.

Considérez le problème suivant:

Que se passe-t-il s'il y a une erreur de logique dans la classe A qui entraîne son écriture dans la mémoire qui appartient maintenant à la classe B?

Dans ce cas particulier, vous n'obtiendrez pas d'erreur d'erreur d'exception d'accès incorrect, car l'adresse de la mémoire est légale, alors que la classe A altère désormais efficacement les données de la classe B.

La classe B peut éventuellement tomber en panne si elle rencontre des valeurs inattendues. Si elle tombe en panne, il y a de fortes chances que vous passiez un long moment à rechercher ce bogue en classe B lorsque le problème est en classe A.

Si vous aviez défini le pointeur de la mémoire supprimée sur NULL, vous auriez reçu une erreur d'exception dès qu'une erreur de logique de la classe A aurait tenté d'écrire dans le pointeur NULL.

Si vous vous inquiétez de l'erreur de logique avec la double suppression lorsque les pointeurs sont NULL pour la deuxième fois, ajoutez alors assert pour cela.

Aussi: si vous votez à la baisse, veuillez expliquer.

1
John

Il existe plusieurs façons d’écrire des instructions de contrôle. certaines combinaisons peuvent coexister sans nuire à la lisibilité, mais d’autres peuvent causer des problèmes. Le style

if (condition)
  statement;

coexistera confortablement avec certaines des autres façons d’écrire des déclarations de contrôle, mais pas aussi bien avec d’autres. Si les instructions contrôlées sur plusieurs lignes sont écrites comme suit:

if (condition)
{
  statement;
  statement;
}

alors, il sera visuellement évident de savoir quelles instructions if contrôlent une seule ligne et lesquelles contrôlent plusieurs lignes. Cependant, si les instructions multi-lignes if sont écrites comme suit:

if (condition) {
  statement;
  statement;
}

il est alors beaucoup plus probable que quelqu'un essaye d'étendre une construction à instruction unique if sans ajouter les accolades nécessaires.

L'instruction à instruction suivante sur la ligne suivante if peut également poser problème si la base de code utilise de manière significative le formulaire

if (condition) statement;

Ma propre préférence est que le fait d'avoir l'instruction sur sa propre ligne améliore généralement la lisibilité, sauf dans les cas où il existe de nombreuses instructions if avec des blocs de contrôle similaires, par exemple.

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

dans ce cas, je vais généralement précéder et suivre ces groupes d'instructions if avec une ligne vide pour les séparer visuellement des autres codes. Avoir une gamme d'énoncés qui commencent tous par if à la même indentation donnera alors une indication visuelle claire qu'il y a quelque chose d'inhabituel.

1
supercat