2010-04-27 5 views
1

Nous savons que le compilateur génère des fonctions membres pour la classe définie par l'utilisateur si ces fonctions membres sont non défini mais utilisé, n'est-ce pas? J'ai donc ce genre de code:Problème avec les fonctions membres par défaut de la classe en C++ (constructeur, destructeur, opérateur =, constructeur de copie) (par défaut ctor, dtor, copy ctor)

class AA 
{ 
}; 

void main() 
{ 
    AA a; 
    AA b(a); 
    a = b; 
} 

Ce code fonctionne très bien. Je veux dire aucune erreur de compilation. Mais le code suivant ....

class AA 
{ 
    int member1; 
    int member2; 
}; 

Mais ce code donne une erreur de temps d'exécution, car la variable « a » est utilisé sans être iniltialized !!! Donc, ma question est la suivante: lorsque nous instancions un int, il a une valeur. Alors pourquoi le constructeur par défaut ne fonctionne pas et en utilisant ces deux nombres int initialise la variable "a" ??

EDIT: Plate-forme: Win Vista, compilateur: compilateur Visual Studio 2008; Drapeaux: Par défaut

+2

quel type d'erreur d'exécution? – Glen

+0

Ecriture seconde fois: la variable "a" est utilisée sans être inlialisée !!! – Narek

+0

Peut-être dans votre compilateur "/ WX" (traiter les avertissements en tant qu'erreurs)? –

Répondre

6

Le constructeur par défaut compilé par synthétiseur appelle les constructeurs par défaut pour tous les membres de la classe qui ont des constructeurs. Mais les entiers n'ont pas de constructeur et ne sont donc pas initialisés. Cependant, j'ai du mal à croire que cela provoquera une erreur d'exécution.

Pour initialiser les variables:

class AA { 
    public: 
    AA() : member1(0), member2(0) {} 
    private: 
    int member1; 
    int member2; 
}; 
+0

+1, le niveau d'effort pour initialiser les variables membres est minime et beaucoup plus propre. – Robb

0

Quelle plateforme? compilateur? drapeaux du compilateur? Vous devez ajouter une vérification supplémentaire car il n'y a rien dans le C++ normal qui vérifie l'état d'initialisation.

0

En fait, la valeur par défaut et les constructeurs de copie fonctionnent. Mais dans cpp les variables non initialisées contiennent en réalité des ordures. Par conséquent, vous obtenez votre erreur (int member1, int member2 contient la corbeille et vous essayez d'affecter cette corbeille à l'objet b).

+0

Comment comprend-il que c'est trash pas une valeur que j'ai assignée ?? – Narek

+0

@Narek certains compilateurs C++, lors de la construction de code pour le débogage, vont remplir les variables non initialisées avec une valeur spéciale (je pense que Visual C++ utilise 0xCDCDCDCD) qui lui permet de détecter cela. Ma conjecture est que le constructeur de copie généré par le compilateur vérifie les champs de l'objet qu'il copie pour essayer d'attraper ce type d'erreur. Toutefois, ne dépendez pas de cela dans les versions de versions: dans les versions de versions, elles ne contiennent que les données déjà présentes dans cette mémoire. –

+0

0xCDCDCDCD est seulement utilisé pour remplir des allocations de tas, pas de pile (variables locales). Et un int avec une valeur 0xCDCDCDCD est valide (-842150451), déréférencement d'un pointeur avec 0xCDCDCDCD serait piège, mais pas en utilisant un int. – progrmr

0

Tout d'abord, lorsque vous instanciez un int sans l'initialiser, il a une valeur indéterminée. Un type de base intégré n'a pas de constructeur. En second lieu, ce code ne doit pas générer une erreur d'exécution. Il copie simplement les valeurs int indéterminées dans le constructeur de copie générée automatiquement et les opérateurs d'affectation. Il devrait générer un compilateur avertissant qu'une variable non initialisée est utilisée.

En troisième lieu, votre signature principale est erronée - la signature correcte est

int main(void) 
+0

Cela change-t-il quelque chose, quand vous écrivez int main (void), au lieu de int main() ??? – Narek

+0

Cela devient correct selon la norme C++ :) Sinon, pas beaucoup de changements - mais vous pouvez utiliser la valeur de retour pour spécifier le succès ou l'échec, utile pour "enchaîner" des programmes. –

+3

Narek, il n'y a pas de différence entre int main (void); et int main(); mais vous ne devriez pas utiliser void main() –

1

Tout d'abord, du point de vue pratique est pas une erreur véritable exécution. Ceci est une fonctionnalité intégrée de débogage de votre environnement de développement. Le compilateur tente d'attraper des situations lorsque vous lisez une valeur non initialisée, ce qui est exactement ce qui se passe dans votre cas.

Deuxièmement, lorsque nous "instancions" un int, il n'a pas de valeur. Plus précisément, il contient une valeur indéterminée dont la stabilité n'est même pas garantie (vous pouvez obtenir différentes valeurs en lisant plusieurs fois de suite la même variable non initialisée). Théoriquement, la lecture d'une variable int non initialisée conduit à un comportement indéfini, car il peut contenir une représentation illégale ("trap"). En fait, vous pouvez percevoir votre "erreur d'exécution" générée par votre environnement de développement comme une manifestation de ce comportement indéfini.

+0

Dans un appel de fonction, les variables locales non initialisées sont stables (elles ne varieront pas), mais chaque appel à une fonction réattribue les variables locales et toutes les valeurs se trouvent dans la mémoire de la pile à ce moment. De plus, un int ne peut pas contenir une représentation de trap, toutes les valeurs d'un int sont valides, vous ne savez pas quelle valeur vous obtiendrez quand il n'est pas initialisé. – progrmr

+0

@ kk6yb: Non, absolument incorrect. Premièrement, ils ne sont pas stables dans le cas général. La langue ne fait pas de telles garanties et l'instabilité est souvent reproductible dans la pratique. L'instabilité se produit en pratique lorsque la variable est représentée par un registre de CPU et que l'on y accède en dehors de cette "durée de vie de valeur", c'est-à-dire lorsque le registre est réellement utilisé pour une autre variable. La pile de mémoire a très peu à voir avec cela dans le cas général. – AnT

+0

@ kk6yb: Deuxièmement, le seul type en C++ qui ne peut contenir une représentation d'interruption est 'unsigned char' (c'est-à-dire que tous les modèles de bits sont valides). Tous les autres types, y compris 'int', peuvent contenir une représentation d'interruption. – AnT

Questions connexes