jeudi 19 juillet 2012

Non-static data member initializers

Voici un petit changement dans C++11 qui semble tout droit venir de Java. L'idée est de permettre l'initialisation des membres non-statiques au niveau de leur déclaration. Voyons tout de suite ce à quoi cela peut ressembler:

#include <string>
#include <iostream>

class A
{
public:
  int a = 3;
  std::string b = "abc";
};

int main()
{
  A a;
  std::cout << a.a << ", " << a.b << std::endl;

  return 0;
}

Compilons (remarquons au passage que si l'on ne spécifie pas l'option "--std=c++11", l'on a un petit warning du type "init.cpp:7:11: warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11 [enabled by default]"). Comme prévu, le programme affiche "3, abc".

Remarquons également qu'il est possible d'utiliser des fonctions libres, ou encore des méthodes, pour initialiser ses variables, et qu'il est également possible d'utiliser les listes d'initialisation, soit avec le "=" réglementaire, soit en accolant les {} directement après la variable.

class A
{
public:
  int a = 3;
  std::string b = thestring();
  std::vector<int> c = {1, 2, 3, 4, 5};
  std::vector<double> d{1, 2, 3, 4, 5};

  std::string thestring()
  {
    return "abc";
  }
};

Il est possible de forcer la valeur dans un constructeur, ce qui permet d'implémenter une valeur par défaut: dans l'exemple suivant, _batchSize vaut soit 1000 pour le constructeur par défaut, soit la valeur passée en paramètre pour l'autre constructeur.

class A
{
public:
  A()
  {
  }
  
  A(int batchSize):
  _batchSize(batchSize)
  {
  }
  
  int _batchSize = 1000;
};

Alors, utile? Certainement. Un des gros avantages de ce type de notation est de réduire la duplication de code lorsqu'une classe a beaucoup de constructeurs qui initialisent tous certaines variables à la même valeur, réduisant le risque d'erreurs (pensez à une variable "isRunning" par exemple). En revanche, et c'est mon souci principal, cela augmente le nombre d'endroits où les initialisations sont effectuées, rendant le code plus difficile à lire: il n'est pas suffisant de regarder son constructeur, il faut également aller dans le fichier d'en-tête pour voir à quoi seront initialisées les autres valeurs. Pour cette raison, il sera probablement sage de limiter cette fonctionnalité aux classes relativement simples, ou à certains membres bien définis (typiquement, les variables changent peu, liées à l'état de la classe, comme les batchSize, isRunning, objectName...). Mais dans des classes très complexes, c'est risquer de rendre le code bien moins compréhensible.

Aucun commentaire: