2017-08-24 6 views
-1

Disons que vous avez ceci: (code boilerplate omis)Qu'arrive-t-il aux objets déclarés à l'intérieur d'une fonction et utilisés comme valeur de retour? Pourquoi ne sont-ils pas désaffectés sur le retour?

static Object foo() 
{ 
    Object test = new Object(); 
    return test; 
} 

Object output = foo(); 

au moins en C#, le programme ne tombe pas en panne lorsque vous essayez d'utiliser la sortie même si elle pointe vers le même objet déclaré dans foo. Pourquoi n'a-t-il pas été immédiatement désaffecté? Et si c'est une mauvaise façon de gérer les valeurs de retour d'objet, y a-t-il une meilleure façon de le gérer?

+1

"Pourquoi ne l'avez-vous pas immédiatement désaffecté?" Parce que le garbage collection, et nous passons des références. L'amour en C# n'a jamais à dire que vous avez terminé. –

+0

"L'amour en C# n'a jamais à dire que vous avez terminé." - C'est profond @JeroenMostert: D Ken: En assignant la référence 'output' il y a une forte référence à l'objet créé dans la fonction. C'est pourquoi le GC ne le recueillera pas. Pourquoi serait-ce "un mauvais moyen de gérer les valeurs de retour d'objet"? Sinon, comment retourneriez-vous un type de référence? – Fildor

+2

Retournez-vous, pourquoi * devrait * le programme plantage? N'est-ce pas clair ce que vous voulez faire ici? Souhaitez-vous que le programme se bloque parce que vous ne lui avez pas dit explicitement de faire une copie appropriée pour l'accès en dehors de la fonction? Aimeriez-vous savoir exactement ce qu'il y a sur la pile et ce qu'il y a sur le tas à chaque instant?Si vous avez dit «oui», vous pouvez avoir une carrière merveilleuse en tant que programmeur C - mais vous (surtout) n'avez pas besoin de porter ce bagage mental lorsque vous programmez C#. –

Répondre

0

Référence passant. L'objet est un type de référence, ce qui signifie que chaque changement effectué (y compris l'allocation) sera conservé sur le bloc où cet objet a été déclaré.

Si vous avez fait du C/C++, les références sont des pointeurs un peu automatisés.

Retour ce n'est pas une mauvaise pratique, mais il faut faire attention à ce sujet. Lorsque vous renvoyez la référence et l'affectez plus tard, vous perdez la version précédente si vous l'avez déjà allouée auparavant. Encore une fois, si vous avez fait du C, c'est comme si vous faisiez pointer le pointeur sur une seconde partie de mémoire allouée, en laissant le premier (dans l'exemple précédent).

2

Le GC ne recueillera (s'il le désire) que des objets qui n'ont pas de références accessibles. Dans votre exemple:

static object foo() 
{ 
    object test = new object(); 
    return test; 
} 

object output = foo(); 

L'instance référencée par test est également référencé par output lorsque foo retours. Donc même si test n'est plus accessible référence, output est toujours, par conséquent, l'instance de son "pointage" n'est pas un candidat pour la collecte.

L'exemple suivant est radicalement différent:

static object foo() 
{ 
    object test = new object(); 
    return test; 
} 

foo(); 

Ici, l'instance référencée par testest un candidat valide pour la collecte une fois foo retours (ou même avant, mais permet d'ignorer ces optimisations) car une fois foo renvoie, il n'y a pas de références accessibles à l'objet.

Notez que j'utilise joignable références. Un objet peut avoir des références valides le référençant mais être toujours candidat à la collecte si l'objet contenant la référence est également candidat à la collecte. Le GC est assez intelligent à propos de ces types de cycles:

class A { public B b; } 
class B { public A a; } 

void Foo() 
{ 
    A a = new A(); 
    B b = new B(); 
    a.B = b; 
    b.A = a; 
} 

Foo(); //both a and b are elegible for collection once Foo exists.