Question

Je suis partie à l'aide de listes d'initialisation membres avec mes constructeurs ... mais je l'ai depuis longtemps oublié les raisons de cette ...

Utilisez-vous des listes d'initialisation de membres dans vos constructeurs? Si oui, pourquoi? Sinon, pourquoi pas?

Autres conseils

En dehors des raisons de performance mentionnés ci-dessus, si votre classe stocke des références à des objets en tant que paramètres passés du constructeur ou votre classe a des variables const alors vous n'avez pas d'autre choix que d'utiliser des listes de initialiseur.

  1. Initialisation de classe de base

Une raison importante pour l'utilisation de la liste d'initialisation du constructeur qui ne figure pas dans les réponses ici est l'initialisation de la classe de base.

Selon l'ordre de construction, la classe de base doit être construite avant la classe des enfants. Sans liste d'initialisation du constructeur, cela est possible si votre classe de base a constructeur par défaut qui sera appelé juste avant d'entrer dans le constructeur de la classe enfant.

Mais, si votre classe de base a seulement constructeur paramétrés, vous devez utiliser la liste d'initialisation du constructeur pour vous assurer que votre classe de base est initialisé avant la classe de l'enfant.

  1. Initialisation de sous-objets qui ont seulement constructeurs paramétrés

  2. Efficacité

En utilisant la liste d'initialisation du constructeur, vous initialisez vos membres de données à l'état exact dont vous avez besoin dans votre code plutôt que d'abord les initialiser à leur état par défaut et puis en changeant leur état à celui dont vous avez besoin dans votre code.

  1. Initialiser membres de données const non statiques

Si les membres de données const non statiques dans votre classe ont des constructeurs par défaut et ne pas utiliser la liste d'initialisation du constructeur, vous ne serez pas en mesure de les initialiser à l'état prévu car ils seront initialisées à leur état par défaut.

  1. Initialisation des membres de données de référence

membres de données de référence doivent être intialized lorsque le compilateur entre constructeur comme références ne peuvent pas être simplement déclarés et initialisés plus tard. Ceci est possible uniquement avec la liste d'initialisation du constructeur.

À côté des problèmes de performance, il y a un autre très important que je qualifierais le code maintenabilité et extendibility.

Si T est POD et vous commencez à préférer la liste d'initialisation, alors si un temps T va changer à un type non-POD, vous aurez pas besoin de changer quoi que ce soit autour de l'initialisation pour éviter les appels constructeur inutile car il est déjà optimisé.

Si le type T n'ont constructeur par défaut et un ou plusieurs constructeurs définis par l'utilisateur et une fois que vous décidez de supprimer ou de masquer la valeur par défaut d'un, alors si la liste d'initialisation a été utilisé, vous n'avez pas besoin de mettre à jour le code si votre user- constructeurs définis parce qu'ils sont déjà mis en œuvre correctement.

Même avec les membres const ou des membres de référence, disons que T est d'abord défini comme suit:

struct T
{
    T() { a = 5; }
private:
    int a;
};

Ensuite, vous décidez de qualifier un const, si vous utilisez la liste d'initialisation depuis le début, alors ce fut un seul changement de ligne, mais ayant le T défini comme ci-dessus, il faut aussi creuser la définition du constructeur pour supprimer l'affectation :

struct T
{
    T() : a(5) {} // 2. that requires changes here too
private:
    const int a; // 1. one line change
};

Il est pas un secret que l'entretien est beaucoup plus facile et moins sujette aux erreurs si le code a été écrit non pas par un « singe de code » mais par un ingénieur qui prend des décisions basées sur un examen plus approfondi de ce qu'il fait.

Avant que le corps du constructeur est exécuté, tous les constructeurs pour la classe parente, puis pour ses champs sont appelés. Par défaut, les constructeurs sont appelés sans argument. listes d'initialisation vous permettent de choisir quel constructeur est appelé et quels sont les arguments que le constructeur reçoit.

Si vous avez une référence ou un champ const, ou si l'une des classes utilisées ne dispose pas d'un constructeur par défaut, vous devez utiliser une liste d'initialisation.

// Without Initializer List
class MyClass {
    Type variable;
public:
    MyClass(Type a) {  // Assume that Type is an already
                     // declared class and it has appropriate 
                     // constructors and operators
        variable = a;
    }
};

Ici suit compilateur suivant les étapes pour créer un objet de type MyClass
     1. Le constructeur de type est appelé d'abord pour « un ».
    2. L'opérateur d'affectation de « type » est appelé l'intérieur du corps du constructeur MaClasse () pour affecter

variable = a;
  1. Et puis enfin de destructor « Type » est appelé à « un », car il est hors de portée.

    Considérons maintenant le même code avec le constructeur MaClasse () avec Initializer Liste

    // With Initializer List
     class MyClass {
    Type variable;
    public:
    MyClass(Type a):variable(a) {   // Assume that Type is an already
                     // declared class and it has appropriate
                     // constructors and operators
    }
    };
    

    Avec la liste Initializer, les étapes suivantes sont suivies par le compilateur:

    1. Copie constructeur de classe « Type » est appelée à initialiser: variable (a). Les arguments dans la liste des initialiseur sont utilisés pour copier construire « variable » directement.
    2. Destructeur de « type » est appelé à « un », car il est hors de portée.

Juste pour ajouter des informations supplémentaires pour montrer à quel point la différence de la liste d'initialisation du membre peut mak . Dans le leetcode 303 Range Somme Requête - Immuable, https://leetcode.com/problems / gamme somme requête immuable / , où vous devez construire et initialiser à zéro avec un vecteur certaine taille. Voici deux implémentations différentes et la comparaison vitesse.

Sans initialisation membre liste, pour obtenir AC il m'a coûté environ 212 ms .

class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
    preSum = vector<int>(nums.size()+1, 0);
    int ps = 0;
    for (int i = 0; i < nums.size(); i++)
    {
        ps += nums[i];
        preSum[i+1] = ps;
    }
}

int sumRange(int i, int j) {
    return preSum[j+1] - preSum[i];
}
};

en utilisant la liste d'initialisation des membres , le temps de AC est sur 108 ms . Avec cet exemple simple, il est tout à fait évident que, Liste d'initialisation de membre est une façon plus efficace . Toute la mesure est en cours d'exécution à partir du moment de la LC.

class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) { 
    int ps = 0;
    for (int i = 0; i < nums.size(); i++)
    {
        ps += nums[i];
        preSum[i+1] = ps;
    }
}

int sumRange(int i, int j) {
    return preSum[j+1] - preSum[i];
}
};

Syntaxe:

  class Sample
  {
     public:
         int Sam_x;
         int Sam_y;

     Sample(): Sam_x(1), Sam_y(2)     /* Classname: Initialization List */
     {
           // Constructor body
     }
  };

Nécessité de la liste d'initialisation:

 class Sample
 {
     public:
         int Sam_x;
         int Sam_y;

     Sample()     */* Object and variables are created - i.e.:declaration of variables */*
     { // Constructor body starts 

         Sam_x = 1;      */* Defining a value to the variable */* 
         Sam_y = 2;

     } // Constructor body ends
  };

dans le programme ci-dessus, lorsque le constructeur de la classe est exécutée, Sam_x et Sam_y sont créés. Ensuite, dans le corps du constructeur, les variables de données membres sont définies.

Les cas d'utilisation:

  1. Const et les variables de référence dans une classe

En C, les variables doit définir lors de la création. de la même manière en C ++, il faut initialiser la Const et variable de référence lors de la création d'objets en utilisant la liste d'initialisation. si nous faisons l'initialisation après la création d'objet (corps du constructeur intérieur), nous allons obtenir erreur de compilation de temps.

  1. objets membres de la classe Sample1 (base) qui n'ont pas constructeur par défaut

     class Sample1 
     {
         int i;
         public:
         Sample1 (int temp)
         {
            i = temp;
         }
     };
    
      // Class Sample2 contains object of Sample1 
     class Sample2
     {
      Sample1  a;
      public:
      Sample2 (int x): a(x)      /* Initializer list must be used */
      {
    
      }
     };
    

Lors de la création objet pour la classe dérivée qui appelle en interne dérivé constructeur de la classe et appelle constructeur de la classe de base (par défaut). si la classe de base n'a pas de constructeur par défaut, l'utilisateur obtiendra erreur de compilation de temps. Pour éviter, il faut avoir soit

 1. Default constructor of Sample1 class
 2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
  1. nom du paramètre du constructeur de la classe et le membre de données d'une classe sont les mêmes:

     class Sample3 {
        int i;         /* Member variable name : i */  
        public:
        Sample3 (int i)    /* Local variable name : i */ 
        {
            i = i;
            print(i);   /* Local variable: Prints the correct value which we passed in constructor */
        }
        int getI() const 
        { 
             print(i);    /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
             return i; 
        }
     };
    

Comme nous le savons tous, la variable locale ayant la plus haute priorité alors variable globale si les deux variables ayant même nom. Dans ce cas, le programme considère « i » valeur {variable à la fois gauche et à droite. i.e.: i = i} comme variable locale dans le constructeur Sample3 () et variable membre de classe (i) obtenu override. Pour éviter, il faut utiliser soit

  1. Initialization list 
  2. this operator.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top