35 votes

Pourquoi un constructeur est-il nécessaire dans une structure de membre const?

J'ai un code similaire à ceci:

class AClass {
public:
  struct AStruct { };

  AClass(){}

private:
  const AStruct m_struct;
};

int main() {
  AClass a;
}

Il met cette erreur de compilation (avec Clang LLVM version 5.1):

error: constructor for 'AClass' must explicitly initialize 
       the const member 'm_struct'

Si je spécifie une C++11 constructeur par défaut pour struct AStruct, j'obtiens le même message d'erreur:

  struct AStruct {
    AStruct() = default;
  };

Cependant, ce problème est résolu par l'écriture d'un constructeur dont le corps est vide:

  struct AStruct {
    AStruct(){}  // fixed
  };

Pourquoi ai-je besoin de spécifier un constructeur vide? N'est-il pas créé automatiquement avec un accès public pour les structures?

Pourquoi ne pas le C++11 constructeur par défaut de résoudre le problème?

27voto

chris Points 28950

De §8.5 [dcl.init]/7:

Si un programme d'appels pour l'initialisation par défaut d'un objet d'une const qualifiés de type T, T est un type de classe avec un utilisateur par défaut fourni par le constructeur.

Le constructeur par défaut de AClass -par-défaut initialise l' const membre (voir ci-dessous), de sorte que le membre doit disposer d'un utilisateur par défaut fourni par le constructeur. À l'aide de = default n'entraîne pas un utilisateur par défaut fourni par le constructeur, comme peut être vu dans le §8.4.2 [dcl.fct.def.par défaut]/4:

Une fonction est fourni par l'utilisateur si elle est déclarée et non explicitement par défaut ou supprimé sur sa première déclaration.


Le membre par défaut est initialisée par §12.6.2 [classe.de la base.init]/8:

Dans un non-la délégation de constructeur, si un non-membre de données statiques ou de la classe de base n'est pas désigné par un mem-initialiseur-id (y compris dans le cas où il n'y a pas de mem-initialiseur-liste parce que le constructeur n'a pas ctor-initialiseur) et l'entité n'est pas une classe de base virtuelle d'une classe abstraite (10.4), puis

- si l'entité est un non-membre de données statiques qui a un corset ou égal initialiseur , l'entité est initialisé comme spécifié dans les 8.5;
- sinon, si l'entité est un anonyme, un syndicat ou une variante membre (9.5), pas d'initialisation est effectuée;
- sinon, l'entité est par défaut-initialisé (8.5).

17voto

Yakk Points 31636

Volé @chris réponse que nous avons ce paragraphe: §8.5 [dcl.init]/7:

Si un programme d'appels pour l'initialisation par défaut d'un objet d'une const qualifiés de type T, T est un type de classe avec un utilisateur par défaut fourni par le constructeur.

On peut alors construire un complètement ridicule de cas qui illustre cette restriction:

struct Foo {};
int main() {
  const Foo f;
}

qui ne peut pas compiler en clang, comme la norme l'exige. Votre code est simple, mais comme une variable membre d'une autre classe/struct.

Nous pouvons même le faire:

struct Foo {int x = 3;};
int main() {
  const Foo f;
}

où toutes les données sont évidemment initialisé. Ce dernier exemple me convainc que c'est un défaut dans la norme.

La pensée était probablement quelque chose à voir avec la GOUSSE types de initialisé et const, mais le libellé de blocs de code qui n'est pas lié. Constructeurs par défaut en C++ moderne sont souvent plus que suffisant, et en forçant Foo(){} est une mauvaise forme.

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