web-dev-qa-db-fra.com

C++ - initialisation de variables dans en-tête vs avec constructeur

En ce qui concerne ce qui suit, y a-t-il des raisons de faire l'une sur l'autre ou sont-elles à peu près équivalentes?

class Something
{
    int m_a = 0;
};

contre

class Something
{
    int m_a;
    Something(int p_a);
};

Something::Something(int p_a):m_a(p_a){ ... };
28
Evan Ward

Les deux extraits de code que vous avez publiés sont pas tout à fait égaux .

class Something
{
    int m_a = 0;
};

Ici, vous spécifiez la valeur avec laquelle initialiser, c'est-à-dire 0, au moment de la compilation.

class Something
{
    int m_a;
    Something(int p_a);
};

Something::Something(int p_a):m_a(p_a){ ... };

Et ici, vous le faites à run time (ou éventuellement à l'exécution), avec la valeur p_a inconnue jusqu'à l'appel du constructeur.

Le code suivant se rapproche de votre premier exemple:

class Something
{
    int m_a;
    Something();
};

Something::Something() : m_a(0) { /* ... */ };

Ce que vous devez considérer ici est que dans le premier cas, la valeur apparaît directement dans la définition de la classe. Cela peut créer une dépendance inutile. Que se passe-t-il si vous devez changez votre 0 en 1plus tard? Exposer la valeur directement dans la définition de classe (et donc, généralement, dans un fichier d'en-tête) peut provoquer la recompilation d'un lot de code dans des situations où l'autre forme d'initialisation l'éviterait, car la partie Something::Something() : m_a(0) sera parfaitement encapsulée dans une source fichier et ne pas apparaître dans un fichier d'en-tête:

// Something.h - stable header file, never changed
class Something
{
    int m_a;
    Something();
};

// Something.cpp - can change easily
Something::Something() : m_a(0) { /* ... */ };

Bien entendu, les avantages de l'initialisation en classe peuvent largement compenser cet inconvénient. Ça dépend. Vous devez juste garder cela à l'esprit.

36
Christian Hackl

La première forme est plus pratique si vous avez plusieurs constructeurs (et souhaitez tous initialiser le membre de la même manière), ou si vous n'avez pas besoin d'écrire un constructeur.

La seconde est requise si l’initialiseur dépend d’arguments du constructeur ou s’il est trop compliqué pour une initialisation en classe; et peut-être mieux si le constructeur est compliqué, garder toute l'initialisation au même endroit. (Et cela est également nécessaire si vous devez prendre en charge des compilateurs antérieurs à C++ 11.)

12
Mike Seymour

La première forme est nouvelle dans C++ 11 et, par conséquent, elle n’est pas très bien supportée, en particulier si vous devez prendre en charge une variété de compilateurs plus anciens.

Sinon, ils devraient être à peu près équivalents lorsqu'un compilateur C++ 11 est disponible.

5
Mark B

Expliquer la réponse de Christian Hackl.

Le premier formulaire permet d’initialiser m_a et d’avoir un c'tor par défaut en même temps. Ou vous pouvez même être explicite dans votre code et définir un constructeur avec le mot clé default:

class Something
{       
    int m_a = 0;

    // explicitly tell the compiler to generate a default c'tor
    Something() = default;
};

Avec le second formulaire, un c'tor par défaut généré automatiquement laisserait m_a non initialisé. Par conséquent, si vous souhaitez initialiser une valeur codée en dur, vous devez écrire votre propre c'tor par défaut:

class Something
{
    int m_a;

    // implement your own default c'tor
    Something() : m_a(0) {}
};
3
Alexey Polonsky
class Something
{
    int m_a = 0;
};

est équivalent à 

class Something
{
    int m_a(0);
};

Alors, faire 

class Something
{
    int m_a;// (0) is moved to the constructor
public:
    Something(): m_a(0){}
};

génère une syntaxe uniforme pour l'initialisation, qui nécessite ou non une entrée au moment de l'exécution.

Personnellement, je n'aime pas le premier formulaire car il ressemble à une "déclaration puis une cession", ce qui est une idée fausse totale.

0
user3528438