Quel désordre! L'ensemble du programme est très difficile à lire en raison du choix des noms d'identification pour commencer:
#ifndef DELETE
#define DELETE(var) delete var, var = NULL
#endif
Je trouve cela très laid. Lors de l'utilisation des classes, il semble très un-nessacery. Vous pouvez l'utiliser là où une variable est hors de portée mais c'est un gaspillage de temps dans le destructeur. Je pense que ce serait Asier d'envelopper le code dans un pointeur intelligent:
class Teste
{
private:
Teste *_Z;
public:
Teste()
~Teste() // Delete the _Z pointer.
Teste *Z();
void Z(Teste *value);
};
Ok. Vous avez un membre de pointeur que vous supprimez dans le destructeur. Cela signifie que vous prenez possession du pointeur. Cela signifie que l'ule de quatre s'applique (semblable à la règle de trois mais applicable aux règles de propriété). Cela signifie que vous devez écrire 4 méthodes ou que les versions générées par le compilateur gâcheront votre code. Les méthodes que vous devez écrire sont:
A Normal (or default constructor)
A Copy constructor
An Assignment operator
A destructor.
Votre code n'en a que deux. Vous devez écrire les deux autres. Ou votre objet ne doit pas devenir propriétaire du pointeur RAW. c'est à dire. utilisez un Smart Pointer.
Teste *_Z;
Ce n'est pas autorisé. Les identifiants commençant par un tiret bas et une lettre majuscule sont réservés. Vous courez le risque de voir une macro de système d'exploitation corrompre votre code. Arrêtez d'utiliser un trait de soulignement comme premier caractère des identifiants.
~Teste(){
if (_Z != NULL)
DELETE(_Z);
}
Ce n'est pas nécessaire. Asimple supprimer _Z aurait été bien. _Z est hors de portée car il est dans le destructeur, donc pas besoin de le mettre à NULL. L'opérateur delete gère correctement les pointeurs NULL.
~Test()
{ delete _Z;
}
Teste *Z(){
_Z = new Teste;
return _Z;
}
Qu'est-ce qui se passe si vous appelez Z() plusieurs fois (PS mettre le * à côté du Z plutôt que à côté de la rendre difficile Teste à lire). Chaque fois que vous appelez Z(), la variable membre _Z reçoit une nouvelle valeur. Mais qu'arrive-t-il à l'ancienne valeur? Fondamentalement, vous le fuyez. En retournant un pointeur sur un objet appartenant à dans Teste, vous donnez à quelqu'un d'autre la possibilité d'abuser de l'objet (supprimez-le etc). Ce n'est pas bien. Il n'y a pas de propriété claire indiquée par cette méthode.
Teste& Z()
{
delete _Z; // Destroy the old value
_Z = new Teste; // Allocate a new value.
return *_Z; // Return a reference. This indicates you are retaining ownership.
// Thus any user is not allowed to delete it.
// Also you should note in the docs that it is only valid
// until the next not const call on the object
}
void Z(Teste *value){
value->AnyNum = 100;
*_Z = *value;
}
Vous copiez le contenu d'un objet nouvellement construit (qui contient un pointeur) dans un autre objet créé dynamiquement! Que se passe-t-il si _Z n'a pas été attribué en premier. Le constructeur le définit à NULL donc il n'y a aucune garantie qu'il a une valeur valide. Tout objet que vous allouez doit également être supprimé. Mais ici la valeur est allouée dynamiquement passée en Z mais jamais libérée. La raison pour laquelle vous vous en débarrassez est que le pointeur est c activé dans _Z et que _Z est supprimé lorsque son destructeur est détruit.
Teste *b = new Teste, *a;
qui est vraiment entendu lire. Don; t être paresseux l'écrire correctement. Ceci est considéré comme un mauvais style et vous ne pourriez jamais passer en revue le code avec cela.
Teste* b = new Teste;
Teste* a; // Why not set it to NULL
a = b->Z();
Obtenir objet ab pour un. Mais qui détruisait l'objet a ou b?
b->Z(new Teste);
Cela devient juste trop compliqué après cela.
Vous pouvez toujours utiliser valgrind pour tester les fuites de mémoire . C'est très efficace. –
Ouais, je l'utilisais parfois avant avec C et c'était plutôt sympa. – Jonathan
Je pense que la meilleure façon d'être sûr de ne pas laisser échapper de la mémoire est de ne pas essayer de faire des folies. Qu'est-ce que c'est: une classe dont le but est de contenir un entier ** et ** de tenter de gérer la mémoire d'une autre instance dynamiquement allouée de lui-même? – UncleBens