Je viens de réaliser que ce programme compile et exécute (Version GCC 4.4.5 / Ubuntu):
Test method(Test& t) { cout << "in some" << endl; return t; }
6 Réponses :
Si vous manivez vos niveaux d'avertissement, votre compilateur vous avertira probablement d'utiliser des éléments non initialisés. Ub ne veut pas besoin em> un diagnostic, de nombreuses choses qui sont "évidemment" mal peuvent compiler. P>
$ g ++ -wall -petic -o ttst Tst.cpp Tst.cpp Tst.cpp: en fonction 'int Main (int, char * **)': TST.CPP: 21: AVERTISSEMENT: 'I' est utilisé non inijialisé dans cette fonction Tst.cpp : 23: AVERTISSEMENT: 'B' est utilisé ininitialisé dans cette fonction
ideone.com/najvp compile sans avertissements lorsque je compile avec -wall code> et
-peal code>
(était juste pour confirmer Etarion et j'avais ajouté votre int i = i; code> ligne)
@Frankh, à droite, donc avec -wall -peantique code> le
test A (A); code> passe sans avertissements.
Aioobe, oui, voir ma réponse ci-dessous. Je peux expliquer ce comportement mais ne pas le résoudre pour le a (a) code> cas.
Je n'ai aucune idée de la manière dont cela se rapporte à la spécification, mais c'est comme ça que je le vois: p>
Lorsque vous faites Lorsque vous faites Test A (A); code> Il attribue de l'espace pour
A code> sur la pile. Par conséquent, l'emplacement de
A code> en mémoire est connu du compilateur au début de
principal code>. Lorsque le constructeur est appelé (la mémoire est bien sûr allouée auparavant), le pointeur code> ceci est correctement attribué, car il est connu. P>
test * b = nouveau test (* b); code>, vous devez y penser comme deux étapes. D'abord, l'objet est alloué et construit, puis le pointeur à celui-ci est attribué à
B code>. La raison pour laquelle vous obtenez le message que vous obtenez est que vous passez essentiellement dans un pointeur ininitialisé sur le constructeur et le comparant avec le pointeur réel code> de l'objet (qui sera éventuellement attribué à < code> B code>, mais pas avant la sortie du constructeur). p>
Gee, quel était le vote en direct? Cela vous dérangerait-il de pointer ce que j'avais tort?
D'accord. Merci. Vous avez expliqué pour moi pourquoi il est possible de compiler cela. Vous savez que la justification est pour permettre ce type de programme?
@aioobe: Comme je l'ai dit, je ne peux rien dire de la spécification car je ne l'ai pas lu, mais Test A (A) Code> a du sens de manière à une manière, étrange et pervers. Il suffit de passer dans un pointeur sur
A code>, qui a été alloué à ce point (mais non construit). Et autant que je sache, le pointeur ne peut être transmis que sur le constructeur lui-même, ce qui ne dégât aucun dommage que le constructeur a déjà le pointeur de toute façon. Quant au deuxième exemple, il s'agit simplement d'un cas classique d'utiliser un pointeur non initialisé.
Corrigez-moi si je me trompe, mais vous ne voulez pas dire «référence» où vous avez écrit «pointeur»?
Sur la pensée ultérieure, vous pouvez passer probablement à un pointeur à un pointeur à un objet non arrêté à quelque chose d'autre à part le constructeur en faisant test A (quelque chose (a)); code>. Je me demande si cela compile et quelle dit la spécification sur l'objet non arrêté.
@AIOOBE: Une référence est essentiellement un pointeur. Je suis plus d'un programmeur C afin que je puisse me référer à eux en utilisant parfois la mauvaise terminologie. S'il te plaît essaye de comprendre.
Ah. Point intéressant. Bien sûr, il compile et exécute sans avertissements (même avec -wall code> et
-pedantique code>: IDEONE.COM/XDQLC )
Je ne connais pas la référence de spécification, mais je sais que l'accès à un pointeur ininitialisé entraîne toujours un comportement indéfini. p>
Lorsque je compile votre code dans Visual C ++, je reçois: p>
test.cpp (20): AVERTISSEMENT C4700: variable locale non initialisée 'B' utilisée p> blockQuote>
Cette ligne ne compilera même pas dans Visual C ++: Test.cpp (19): Erreur C2065: 'A': identifiant non déclaré code>.
Aha, alors il est encore plus intéressant de savoir quelle est la spécification de la langue à ce sujet. Soit il doit être dépendant du compilateur, soit l'un des visuels C ++ ou G ++ ne se comporte pas selon la spécification.
Le second où vous utilisez nouveau code> est en réalité plus facile à comprendre; Ce que vous invoquez, il y a exactement la même chose que:
Test a(*(&a));
D'accord. Merci. Vous avez expliqué pour moi pourquoi il est possible de compiler cela. Vous savez quelle est la justification pour permettre ce type de programme?
@AIOOBE: Consultez la réponse de YTtril ci-dessous, cela donne une upease. Le contenu de Autre code> peut avoir un sens dans une telle situation, mais son adresse pourrait bien être significative. Une autre situation de cette telle serait d'initialiser l'un de vos objets via
test C (* (test *) null); code> - que cela a du sens ou non dépend de votre cas d'utilisation.
La raison pour laquelle ce "est autorisé" est dû au fait que les règles indiquent qu'une étendue d'identifiants commence immédiatement après l'identifiant. Dans le cas
struct List { List *next; List(List &n) { next = &n; } };
Le premier cas est (peut-être) couvert de 3,8 / 6: p>
Avant que la durée de vie d'un objet ait commencé mais après le stockage qui L'objet occupera a été alloué ou après la vie d'un objet a pris fin et avant la stockage que l'objet occupé est réutilisé ou libéré, tout lvalue qui fait référence à l'objet d'origine peut être utilisé mais seulement de manière limitée. Un tel Lvalue fait référence au stockage alloué (3.7.3.2), et en utilisant les propriétés de le lvalue qui ne dépend pas de sa la valeur est bien définie. P> blockQuote>
Puisque tout ce que vous utilisez de
a code> (et
autre code>, qui est lié à
a code>) avant le début de sa durée de vie est la Adresse, je pense que vous êtes bon: lisez le reste de ce paragraphe pour les règles détaillées. P>
attention à ce que 8.3.2 / 4 dit: "Une référence doit être initialisée pour désigner un objet ou une fonction valide." Il y a une question (en tant que rapport de défectuement sur la norme) quels moyens "valides" dans ce contexte, donc éventuellement, vous ne pouvez donc pas lier le paramètre
autre code> à l'inconstruction (et donc "invalide"? )
a code>. p>
Alors, je suis incertain ce que la norme dit réellement ici - je peux utiliser une lvalue, mais ne pas le lier à une référence, peut-être, auquel cas
a code> n'est pas < / em> bon, tout en faisant passer un pointeur sur
A code> serait correct tant qu'il n'est utilisé que dans les manières autorisées par 3,8 / 5. P>
dans le cas de
B code>, vous utilisez la valeur avant son initialisation (parce que vous le déréférez, ainsi que même si vous l'avez aussi loin,
et d'autres code> Soyez la valeur de
B code>). Cela n'est clairement pas bon. P>
Comme toujours en C ++, il compile car ce n'est pas une violation des contraintes linguistiques, et la norme n'exige pas explicitement un diagnostic. Imaginez les contorsions que les spécifications devraient utiliser afin de mandater un diagnostic lorsqu'un objet est utilisé à titre d'objet utilisé dans sa propre initialisation et imaginez l'analyse des flux de données qu'un compilateur peut avoir à faire pour identifier des cas complexes (il ne peut même pas être possible au moment de la compilation, si le pointeur est en contrebande via une fonction définie à l'extérieur). Plus facile de le laisser comme un comportement indéfini, à moins que quiconque ait de très bonnes suggestions pour la nouvelle langue de la spécification; -) P>
Related: Stackoverflow.com/Questtions/3892098/ ...
En appelant une méthode avec un objet d'intégrité "douteuse", c'est très autorisé. Vous pouvez faire
obj * ptr = null; PTR-> Certainfunc (); code> et, aussi longtemps que
obj :: Quelquesfunc () code> n'accède pas les variables des membres, il va courir avec bonheur. Cela est même utilisé dans certains contextes, faisant des objets NULL résistant à l'encapsulation de toutes les fonctions de membre public dans
si (! This) renvoie / * une erreur * /; code>
@Frankh: Je ne pense pas que ce soit clair. Voir Open-std.org/jtc1/sc22/wg21 /docs/cwg_active.html#232 , et en particulier la note à la fin, "il existe d'autres contextes dans lesquels des lvalues peuvent survenir, telles que l'opérande gauche de. ou. *, qui devrait également être restreint" . Nulle part le standard n'ique-t-il que les conditions que vous décrivez, par exemple AFAIK, elle ne dessine aucune distinction entre appeler une fonction de membre virtuel ou non virtuelle sur un pointeur NULL. Donc, je pense que vous devez compter sur des informations spécifiques à la mise en œuvre à ce que vous décrivez, et je me méfierais que l'optimiseur peut supposer
ceci! = 0 code>.
Je suppose que dans le résumé, il y a une différence entre "Go Highly" (c'est-à-dire "Fonctionne sur ma machine"), et "est très autorisée" (c'est-à-dire "" est garanti par la norme ").