2012-07-23 2 views
1

Désolé d'être confus, au C++ je sais que renvoyer la référence de la variable locale ou les pointeurs peuvent provoquer une exception de mauvaise référence. Je ne suis pas sûr comment c'est en C#?C++ vs C# BadPointer/BadReference?

par exemple

List<StringBuilder> logs = new List<StringBuilder>(); 
void function(string log) 
{ 
    StringBuilder sb = new StringBuilder(); 
    logs.Add(sb); 
} 

à cette fonction un objet local est créé et stocké dans une liste, est-ce grave ou doit se faire d'une autre manière. Je suis vraiment désolé de demander cela, mais je suis confus après avoir codé C++ pendant 2 mois.

Merci.

+0

Votre code est parfaitement valide. Bizarre, mais valide. –

+0

lol, oui c'est bizarre parce que je l'ai écrit ici :) ces fonctions fonctionnent surtout, mais j'ai besoin de savoir si elles sont en sécurité – icaptan

+0

Huh? Ce n'est pas clair à au. C'est une manière acceptable d'ajouter StringBuilders à une liste StringBuilder, bien que le SB soit toujours vide. Peut-être que votre fonction devrait dans un paramètre pour le texte à ajouter à StringBuilder et à son tour, il l'ajoute à la liste. Vous pouvez également raccourcir ce code avec logs.Add (new StringBuilder()); – GrayFox374

Répondre

1

Votre code C# ne renvoie pas de référence d'objet, donc cela ne correspond pas à vos préoccupations. C'est cependant un problème qui n'existe pas en C#. Le CLR ne vous permet pas de créer des objets sur la pile, seulement le tas. Et le garbage collector s'assure que les références d'objets restent valides.

+0

Merci Hans! Votre réponse est claire! – icaptan

1

En C#, le garbage collector gère tous les objets (gérés) que vous créez. Il n'en supprimera pas sauf s'il n'y a plus de référence.

Donc ce code est parfaitement valide. logs conserve une référence à StringBuilder. Le garbage collector le sait, donc il ne le nettoiera pas même si le contexte dans lequel il a été créé est hors de portée.

1

Le cycle de vie de l'objet C# est géré pour vous par le CLR; par rapport à C++ où vous devez faire correspondre chaque nouvelle avec une suppression.

Cependant, en C# vous ne pouvez pas faire

void fun() 
{ 
    SomeObject sb(10); 
    logs.Add(sb); 
} 

-à-dire l'allocation sur la pile, vous devez utiliser un nouveau - donc à cet égard C# et C++ fonctionnent de la même - sauf en ce qui concerne la libération/libérer la référence d'objet.

Il est toujours possible de perdre de la mémoire en C# - mais c'est plus difficile qu'en C++.

+0

merci! Je connais le "nouveau" et vous m'avez fait clair sur CLR! – icaptan

1

Il n'y a rien de mal avec le code que vous avez écrit. C'est principalement parce que C#, comme n'importe quel langage .NET, est un langage "géré" qui fait beaucoup de gestion de la mémoire pour vous. Pour obtenir le même effet en C++, vous devez utiliser explicitement une bibliothèque tierce.

Pour éclaircir certaines des bases pour vous:

En C#, vous traitez rarement avec des « pointeurs » ou « références » directement. Vous pouvez traiter des pointeurs, si vous en avez besoin, mais c'est un code «dangereux» et vous évitez vraiment ce genre de choses à moins de savoir ce que vous faites. Dans les quelques cas où vous faites affaire avec des références (par exemple ref ou out paramètres) la langue cache tous les détails de vous et vous permet de les traiter comme des variables normales. Au lieu de cela, les objets en C# sont définis comme instances de types de référence; Chaque fois que vous utilisez une instance d'un type de référence, il est similaire à l'utilisation d'un pointeur sauf que vous n'avez pas à vous soucier des détails. Vous pouvez créer de nouvelles instances de types de références en C# de la même façon que vous créez de nouvelles instances d'objets en C++, en utilisant l'opérateur new, qui alloue de la mémoire, exécute les constructeurs, etc. Dans votre exemple de code, les deux StringBuilder et List<StringBuilder> sont les types de référence.

L'aspect clé des langages managés qui est important ici est la collecte automatique de place. Au moment de l'exécution, le .NET Framework "sait" quels objets vous avez créés, car vous les créez toujours à partir de son propre tas géré en interne (pas de malloc direct ou rien de semblable en C#). Il "sait" aussi quand un objet est complètement hors de portée - quand il n'y a plus de références à n'importe quel endroit dans votre programme. Une fois que cela se produit, le moteur d'exécution est capable de libérer la mémoire quand il le veut, généralement quand il commence à manquer de mémoire libre, et vous n'avez jamais à le faire. En fait, il n'y a aucun moyen en C# de détruire explicitement un objet géré (bien que vous ayez à nettoyer ressources non gérées si vous les utilisez).

Dans votre exemple, le moteur d'exécution sait que vous avez créé un StringBuilder et l'avez placé dans un List<>; il gardera la trace de cet objet, et tant qu'il sera dans le List<> il restera collé. Une fois que vous l'avez supprimé du List<>, ou que le List<> lui-même s'en va, le moteur d'exécution nettoie automatiquement le StringBuilder pour vous.

+0

merci, vous l'avez fait pour moi plus clair ! Après avoir codé C++, je deviens un peu suspecte ... Je crois que je dois lire un livre sur C#. – icaptan