67 votes

Quels sont vos idiomes de style de codage C ++ préférés

Quels sont vos favoris de codage C++ style idiomes? Je pose la question sur le style ou le codage de la typographie comme où vous avez mis des accolades, il y a des espaces après les mots clés, la taille de tirets, etc. C'est par opposition aux meilleures pratiques ou des exigences comme toujours de la suppression des tableaux avec des delete[].

Voici un exemple de l'un de mes favoris: En C++ de la Classe des initialiseurs, nous avons mis les séparateurs à l'avant de la ligne, plutôt que le dos. Cela rend plus facile de les tenir à jour. Cela signifie également que le contrôle de code source différences entre les versions sont plus propres.

TextFileProcessor::
TextFileProcessor( class ConstStringFinder& theConstStringFinder ) 

    : TextFileProcessor_Base( theConstStringFinder )

    , m_ThreadHandle  ( NULL )
    , m_startNLSearch (    0 )
    , m_endNLSearch   (    0 )
    , m_LineEndGetIdx (    0 )
    , m_LineEndPutIdx (    0 )
    , m_LineEnds      ( new const void*[ sc_LineEndSize ] )
{
    ;
}

71voto

jalf Points 142628

RAII: l'Acquisition de Ressources Est d'Initialisation

RAII peut-être le plus important de l'idiome. C'est l'idée que les ressources doivent être mappés aux objets, ainsi que leurs durées de vie sont gérées automatiquement, en fonction du cadre dans lequel ces objets sont déclarés.

Par exemple, si un descripteur de fichier a été déclaré sur la pile, il doit être fermé implicitement une fois que nous retournons à partir de la fonction (ou d'une boucle, ou n'importe quel champ d'action qu'elle a été déclarée à l'intérieur). Si une allocation dynamique de la mémoire a été allouée en tant que membre d'une classe, il doit être implicitement libérée une fois que l'instance de classe est détruit. Et ainsi de suite. Tous les types de ressources les allocations de mémoire, les descripteurs de fichiers, de connexions de base de données, prises de courant, et tout autre type de ressource qui doit être acquis et mis en liberté—doit être appliqué à l'intérieur d'un tel RAII de classe, dont la durée de vie est déterminée par le champ d'application dans lequel elle a été déclarée.

Un grand avantage de ceci est que le C++ garantit que les destructeurs sont appelés lorsqu'un objet est hors de portée, indépendamment de la façon dont le contrôle est laisser ce champ d'application. Même si une exception est levée, tous les objets hors de portée, et donc leurs ressources associées seront nettoyés.

void foo() {
  std::fstream file("bar.txt"); // open a file "bar.txt"
  if (rand() % 2) {
    // if this exception is thrown, we leave the function, and so
    // file's destructor is called, which closes the file handle.
    throw std::exception();
  }
  // if the exception is not called, we leave the function normally, and so
  // again, file's destructor is called, which closes the file handle.
}

Indépendamment de la façon dont nous quitter la fonction, et de ce qui se passe une fois le fichier ouvert, nous n'avons pas besoin de fermer explicitement le fichier, ou de gérer les exceptions (par exemple, essayez-enfin) à l'intérieur de cette fonction. Au lieu de cela, le fichier est nettoyée, car il est attaché à un objet local est détruit quand elle est hors de portée.

RAII est également moins communément connu comme SBRM (Champ d'application Lié à la Gestion des Ressources).

Voir aussi:

  • ScopeGuard permet code pour "appeler automatiquement un 'annuler'. dans le cas où une exception est levée."

61voto

kshahar Points 3014

Lors de la création d'énumérations, les mettre dans un espace de noms, de sorte que vous pouvez y accéder avec un nom explicite:

namespace EntityType {
    enum Enum {
        Ground = 0,
        Human,
        Aerial,
        Total
    };
}

void foo(EntityType::Enum entityType)
{
    if (entityType == EntityType::Ground) {
        /*code*/
    }
}

EDIT: Cependant, cette technique est devenue obsolète en C++11. L'étendue de l'énumération (déclarée avec enum class ou enum struct) devrait être utilisée à la place: c'est plus de type-safe, concis, et flexible. Avec l'ancien style énumérations les valeurs sont placés à l'extérieur de la portée. Avec un style nouveau énumération ils sont placés dans le champ d'application de l' enum class nom.
Exemple précédent réécrit à l'aide de l'étendue de l'énumération (aussi connu comme fortement typé énumération):

enum class EntityType {
    Ground = 0,
    Human,
    Aerial,
    Total
};

void foo(EntityType entityType)
{
    if (entityType == EntityType::Ground) {
        /*code*/
    }
}

Il y a d'autres avantages importants de l'utilisation de l'étendue des énumérations: absence de cast implicite, possible de l'avant de la déclaration, et la capacité d'utiliser personnalisée de type sous-jacent (non par défaut int).

40voto

RC. Points 15804

Copier-swap

Le copier-swap idiome fournit exception-safe de la copie. Il faut qu'une copie correcte ctor et swap sont mis en œuvre.

struct String {
  String(String const& other);

  String& operator=(String copy) { // passed by value
    copy.swap(*this); // nothrow swap
    return *this; // old resources now in copy, released in its dtor
  }

  void swap(String& other) throw() {
    using std::swap; // enable ADL, defaulting to std::swap
    swap(data_members, other.data_members);
  }

private:
  Various data_members;
};
void swap(String& a, String& b) { // provide non-member for ADL
  a.swap(b);
}

Vous pouvez également mettre en œuvre la méthode d'échange avec l'ADL (Argument Dépendante de Recherche) directement.

Cet idiome est important car il gère l'auto-affectation[1], du fait de la forte exception de garantie[2], et est souvent très facile à écrire.


[1] Même si l'auto-affectation n'est pas traitée de manière aussi efficace que possible, il est censé être rare, donc si cela n'arrive jamais, c'est effectivement plus rapide.

[2] Si une exception est levée, l'état de l'objet (*this) n'est pas modifié.

23voto

Prembo Points 960

J'aime aligner le code / les initialisations dans les "colonnes" ... s'avère très utile lors de l'édition avec un éditeur capable de gérer le mode "colonne" et semble également être beaucoup plus facile à lire ...

 int myVar        = 1;    // comment 1
int myLongerVar  = 200;  // comment 2

MyStruct arrayOfMyStruct[] = 
{   
    // Name,                 timeout,   valid
    {"A string",             1000,      true    },   // Comment 1
    {"Another string",       2000,      false   },   // Comment 2 
    {"Yet another string",   11111000,  false   },   // Comment 3
    {NULL,                   5,         true    },   // Comment 4
};
 

En revanche, le même code non mis en retrait et formaté comme ci-dessus apparaîtrait ... (un peu plus difficile à lire à mes yeux)

 int myVar = 1; // comment 1
int myLongerVar = 200; // comment 2

MyStruct arrayOfMyStruct[] = 
{   
    // Name, timeout, valid
    {"A string", 1000, true},// Comment 1
    {"Another string", 2000, false }, // Comment 2 
    {"Yet another string", 11111000,false}, // Comment 3
    {NULL, 5, true }, // Comment 4
};
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X