2017-07-28 2 views
1

Je suis encore nouveau à c + + et ai étudié la portée de l'objet.
J'ai testé le code ci-dessous et ai été témoin de certains comportements étranges.Pourquoi ce pointeur est-il valide lorsque son objet est hors de portée? (Et quelques autres comportements étranges)

struct Test 
{ 
    int value, value2; 
    Test() : value(1), value2(10) {}; 
}; 


Test* GetTestPointer() { 
    Test t; 
    t.value = 20; 
    return &t; 
} 

int main() { 
    Test* tp = GetTestPointer(); 
    int a = tp->value; 
    int b = tp->value2; 
    cout << a << endl; 
    cout << b << endl; 

    return 0; 
} 

Sortie:

20 
10 

Je pensais que Test t irait hors de portée si déréférencement ses valeurs dans le principal serait soit jeter une exception ou une valeur vide. Pourquoi obtient-il des valeurs valides comme si l'objet était toujours vivant?

En fait, ce que je l'origine essayé:

Test* tp = GetTestPointer(); 
cout << tp->value << endl; 
cout << tp->value2 << endl; 

Sortie:

20 
18223279 

Ici value2 est d'agir comme il est invalide, mais je peux obtenir value très bien.
Inversement, je les ai essayé réordonnancement:

Test* tp = GetTestPointer(); 
cout << tp->value2 << endl; 
cout << tp->value << endl; 

Sortie:

10 
1459403656 

Notez que rien de tout cela est arrivé lorsque je bien tp avec new initié, comme prévu.

Je sais que je n'écrirais jamais de code comme ça dans la vraie vie, mais je suis vraiment curieux de savoir pourquoi tout cela se passe.

  1. Quand est-ce que t est hors de portée dans ce cas?
  2. Qu'est-ce que la commande de cout a quelque chose à voir avec ce que tp est déréférencement? Pourquoi est-ce que quand je les sauvegarde dans des tampons, est-ce que je peux obtenir les bonnes valeurs?
+1

Vous avez eu de la chance. C'est un comportement indéfini. – tilz0R

+0

_Pourquoi ce pointeur est-il valide_ - il ne l'est pas. Le comportement indéfini est indéfini. –

+0

A quoi ressemblerait une valeur "vide"? – molbdnilo

Répondre

2

vous venez de recevoir la chance d'être une valeur correcte, mais en général il est un comportement non défini et votre compilateur devrait vous avertir à ce sujet.

Essayez d'étendre votre exemple à quelque chose comme ceci:

int my_sum(int a, int b) {return a + b;} 
int main() { 
    int res; 
    Test* tp = GetTestPointer(); 
    res = my_sum(1, 2); 
    int a = tp->value; 
    int b = tp->value2; 
    cout << a << endl; 
    cout << b << endl; 

    return 0; 
} 

Vous verrez une sortie différente parce que votre objet Test scope local a été remplacé par un autre appel de fonction. Lorsque vous utilisez l'instruction new, votre objet n'est pas créé localement, mais dans la mémoire HEAP. Il est donc valide lorsque vous quittez la portée de la fonction. Dans ce cas, vous devez utiliser delete pour supprimer cet objet ultérieurement.

+0

Plus comme malchanceux je suppose. J'ai eu un avertissement que je retournais l'adresse d'un temporaire ... mais sinon, il a compilé et s'est bien passé sans aucune interruption. Est-ce que les comportements non définis passent toujours inaperçus comme ça? Diviser par zéro par exemple mettrait fin à mon programme. – LinguistTroubadour

+0

Vous avez été malchanceux parce que votre programme pourrait échouer dans le futur :) Mais en général, un comportement indéfini peut facilement planter votre exécution :) @LinguistTroubadour – tilz0R