102 votes

Pourquoi C++ requiert un constructeur par défaut fourni par l’utilisateur par défaut-construire un objet const ?

La norme C++ (section 8.5) dit :

Si un programme appelle l’initialisation par défaut d’un objet d’un type qualifié par const T, T doit être un type de classe avec un constructeur par défaut fourni par l’utilisateur.

Pourquoi ? Je ne vois aucune raison pourquoi un constructeur fourni par l’utilisateur est requis dans ce cas.

69voto

Nawaz Points 148870

La raison en est que si la classe n'est pas définie par l'utilisateur et le constructeur, alors il peut être POD, et la GOUSSE de classe n'est pas initialisé par défaut. Donc, si vous déclarez une const objet de POD qui est non initialisée, à quoi ça sert? Je pense donc que la Norme impose cette règle afin que l'objet peut effectivement être utile.

struct POD
{
  int i;
};

POD p1; //uninitialized - but don't worry we can assign some value later on!
p1.i = 10; //assign some value later on!

POD p2 = POD(); //initialized

const POD p3 = POD(); //initialized 

const POD p4; //uninitialized  - error - as we cannot change it later on!

Mais si vous faites de la classe non-POD:

struct nonPOD_A
{
    nonPOD_A() {} //this makes non-POD
};

nonPOD_A a1; //initialized 
const nonPOD_A a2; //initialized 

Notez la différence entre le POD et non-POD.

Défini par l'utilisateur constructeur est une manière de faire de la classe non-POD. Il ya plusieurs façons que vous pouvez faire.

struct nonPOD_B
{
    virtual void f() {} //virtual function make it non-POD
};

nonPOD_B b1; //initialized 
const nonPOD_B b2; //initialized 

Avis nonPOD_B n'est pas défini par l'utilisateur défini constructeur. Compiler. Compiler:

Et le commentaire de la fonction virtuelle, puis il donne une erreur, comme prévu:


Eh bien, je pense que vous avez mal compris le passage. Il est le premier à dire cela (§8.5/9):

Si aucun initialiseur est spécifié pour un objet, et l'objet est de (éventuellement cv qualifiés) non-POD classe type (ou un tableau de celui-ci), l'objet doit être par défaut-initialisé; [...]

Il parle de la non-POD classe , éventuellement de cv qualifiés de type. Qui est, le non-POD objet doit être par défaut-initialisé, si il n'y a pas d'initialiseur spécifié. Et qu'est-ce que par défaut-initialisé? Pour les non-POD, la spec dit (§8.5/5),

À défaut d'initialisation d'un objet de type T signifie:
- si T est un non-POD type de classe (article 9), le constructeur par défaut pour T est appelé (et l'initialisation est mal formé, si T n'a pas de accessible le constructeur par défaut);

Simplement, il parle de constructeur par défaut de T, si ses définies par l'utilisateur ou généré par le compilateur est pas pertinent.

Si vous êtes clair jusqu'à présent, puis de comprendre ce que la spécification suivante est dit ((§8.5/9),

[...]; si l'objet est de const qualifiés de type, le type de classe doit avoir un utilisateur déclaré dans le constructeur par défaut.

Donc, ce texte l'indique, le programme va être mal formé , si l'objet est de const qualifiés de type POD, et il n'y a pas d'initialiseur spécifié (parce que les GOUSSES ne sont pas initialisé par défaut):

POD p1; //uninitialized - can be useful - hence allowed
const POD p2; //uninitialized - never useful  - hence not allowed - error

En passant, cette compile amende, en raison de sa non-POD, et peut être par défaut-initialisé.

12voto

Luc Danton Points 21421

Pure spéculation de ma part, mais considérer que les autres types de restriction semblable, trop:

int main()
{
    const int i; // invalid
}

Ainsi, non seulement est-ce une règle uniforme, mais aussi (de manière récursive) empêche non const (sous -) objets:

struct X {
    int j;
};
struct A {
    int i;
    X x;
}

int main()
{
    const A a; // a.i and a.x.j in unitialized states!
}

Comme pour l'autre côté de la question (en l'autorisant pour les types avec un constructeur par défaut), je pense que l'idée est qu'un type avec un utilisateur par défaut fourni par le constructeur est censé toujours être dans un certain état cohérent après la construction. Notez que les règles qu'ils sont de permettre la suivante:

struct A {
    explicit
    A(int i): initialized(true), i(i) {} // valued constructor

    A(): initialized(false) {}

    bool initialized;
    int i;
};

const A a; // class invariant set up for the object
           // yet we didn't pay the cost of initializing a.i

Alors on pourrait peut-être formuler une règle comme "au moins un membre doit être intelligemment initialisé à un utilisateur par défaut fourni par le constructeur', mais c'est beaucoup trop de temps passé à essayer de se protéger contre Murphy. C++ a tendance à faire confiance au programmeur sur certains points.

1voto

Omnifarious Points 25666

Félicitations, vous avez inventé un cas dans lequel il n'a pas besoin d'être définis par utilisateur constructeur pour l' const déclaration sans initialiseur de sens.

Maintenant, pouvez-vous venir avec une re-formulation de la règle qui couvre votre cas, mais qui fait encore le cas qui devrait être illégal illégal? Est-il inférieur à 5 ou 6 paragraphes? Est-il facile et évident de savoir comment elle devrait être appliquée dans n'importe quelle situation?

Je postulons que venir avec une règle qui permet de la déclaration que vous avez créé pour donner un sens est vraiment dur, et faire en sorte que la règle peut être appliquée d'une manière qui fait sens pour les gens lors de la lecture de code est encore plus difficile. Je préfère un peu restrictive de la règle qui a été la bonne chose à faire dans la plupart des cas à une très nuancée et complexe de la règle qui a été difficile à comprendre et à appliquer.

La question est, est-il une raison impérieuse de la règle doit être plus complexe? Est-il un code qui serait autrement très difficile d'écrire ou de comprendre ce que peut être écrit beaucoup plus simplement, si la règle est plus complexe?

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