0
votes

Pourquoi la mémoire fuit-elle dans un cas et pas dans un autre

Je crée un objet c ++ de deux manières légèrement différentes, dans le code suivant lorsque CASE vaut 0 il y a une fuite de mémoire, mais pas de fuite de mémoire dans le cas else .

valgrind ./a.out 
==24351== Memcheck, a memory error detector
==24351== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==24351== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==24351== Command: ./a.out
==24351== 
==24351== 
==24351== HEAP SUMMARY:
==24351==     in use at exit: 32 bytes in 1 blocks
==24351==   total heap usage: 2 allocs, 1 frees, 72,736 bytes allocated
==24351== 
==24351== LEAK SUMMARY:
==24351==    definitely lost: 32 bytes in 1 blocks
==24351==    indirectly lost: 0 bytes in 0 blocks
==24351==      possibly lost: 0 bytes in 0 blocks
==24351==    still reachable: 0 bytes in 0 blocks
==24351==         suppressed: 0 bytes in 0 blocks
==24351== Rerun with --leak-check=full to see details of leaked memory
==24351== 
==24351== For counts of detected and suppressed errors, rerun with: -v
==24351== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

quand je règle CASE 0 le valgrind dit que il y a une fuite de mémoire

#include <string>
#define CASE 1

class A {
private:
  std::string *s;
public:
  A(std::string *p_s) { s = p_s; }
};

int main() {
#if CASE==0
  auto a = A(new std::string("Hello"));
#else
  auto s = std::string("Hello");
  auto a = A(&s);
#endif
}

dans le cas contraire (ie define CASE 1 ) cela fonctionne comme prévu et valgrind ne signale aucune fuite de mémoire .

Je ne suis pas capable de comprendre dans les deux cas je passe un pointeur et je ne libère pas explicitement la mémoire alors pourquoi se comportent-ils différemment?


1 commentaires

Dans le premier cas, vous allouez de la mémoire avec new , vous devez donc la libérer avec delete . Dans le second cas, il vous suffit de prendre un pointeur vers un objet sur la pile - pas besoin de le supprimer .


4 Réponses :


4
votes

Vous n'obtenez pas de fuite de mémoire car vous avez un pointeur.

Vous obtenez une fuite de mémoire parce que vous avez nouveau quelque chose et ne l'avez pas supprimé .

L'obtention d'un pointeur vers une variable de stockage automatique n'empêche pas la variable d'être nettoyée automatiquement.

En fait, tenter de supprimer & un dans ce cas serait faux / cassé / mal / illégal / hérésie.


0 commentaires

1
votes

Ce n'est pas différent de:

// first case, leak
int *j = new int (5);
//
// second case, no leak
int q = 5;
int *j = &q;

Dans le premier cas, nous avons alloué de la mémoire avec new et il est de notre responsabilité de supprimer code> quand nous avons terminé. Dans le second cas, nous créons q sur la pile et il est détruit quand il est hors de portée.


0 commentaires

5
votes

La raison de ce comportement est que votre classe A n'est pas conçue pour s'approprier std :: string * qui lui est passé: son std :: Le membre string * s suppose que l'objet vers lequel le pointeur est passé au constructeur serait détruit en externe.

Cela conduit à une fuite de mémoire lorsque l'objet n'est pas détruit: delete n'est jamais appelé sur la nouvelle chaîne passée au constructeur dans le premier cas, provoquant une fuite de mémoire .

Dans le second cas, le pointeur pointe vers une chaîne en stockage automatique. Il est détruit à la fin de main , évitant ainsi la fuite de mémoire.


0 commentaires

1
votes

cas == 0 xxx

ceci signifie que vous êtes neuf -ing un objet dans le tas -> Vous devez Explicitement Supprimer - que vous n'aviez pas dans l'extrait de la mémoire -> Fuite de la mémoire.

sinon Xxx

  • auto S = STD :: String ("Hello"); : Cela signifie que vous créez un objet dans la pile et,
  • Auto A = A (& S); : Prenez son adresse (en pile, bien sûr).
  • L'objet créé sera supprimé automatiquement une fois que la variable dépasse

    -> Pas de fuite de mémoire.


0 commentaires