Pourquoi la suppression ne définit-elle pas le pointeur sur NULL?

127

Je me suis toujours demandé pourquoi le réglage automatique du pointeur sur NULL après la suppression ne faisait pas partie de la norme. Si cela est pris en charge, la plupart des plantages dus à un pointeur non valide ne se produiront pas. Mais cela dit, je peux penser à deux raisons pour lesquelles la norme aurait limité cela:

  1. Performance:

    Une instruction supplémentaire pourrait ralentir les deleteperformances.

  2. Serait-ce à cause des constpointeurs.

    Là encore, la norme aurait pu faire quelque chose pour ce cas spécial, je suppose.

Est-ce que quelqu'un connaît les raisons exactes de ne pas permettre cela?

un J.
la source

Réponses:

150

Stroustrup lui-même répond. Un extrait:

C ++ permet explicitement à une implémentation de delete de mettre à zéro un opérande lvalue, et j'avais espéré que les implémentations le feraient, mais cette idée ne semble pas être devenue populaire auprès des implémenteurs.

Mais le principal problème qu'il soulève est que l'argument de delete n'a pas besoin d'être une lvalue.

Dan Olson
la source
Je pense que cela pourrait nécessiter plus d'explications. Je ne suis même pas sûr de ce qu'il dit ... Je suppose que je devrai revenir plus tard quand je pourrai consacrer quelques heures à faire des recherches jusqu'à ce que je l'obtienne. Ou, vous pouvez expliquer la réponse pour nous aider à comprendre plus rapidement.
Gabriel Staples
63

Tout d'abord, définir sur null nécessiterait une variable stockée en mémoire. Il est vrai que vous avez généralement un pointeur dans une variable, mais parfois vous voudrez peut-être supprimer un objet à une adresse juste calculée. Ce serait impossible avec une suppression "annulée".

Puis vient la performance. Vous avez peut-être écrit du code de manière à ce que le pointeur sorte de la portée immédiatement après la suppression . Le remplir avec null est juste une perte de temps. Et C ++ est un langage avec l'idéologie «n'en avez pas besoin?». Vous n'avez donc pas à payer pour cela.

Si vous avez besoin de sécurité, une large gamme de pointeurs intelligents est à votre disposition ou vous pouvez écrire les vôtres - mieux et plus intelligemment.

dents acérées
la source
4
Bon point pour l'adresse calculée, même si c'est quelque chose que vous ne voyez pas souvent
snemarch
parlez-vous de nouveau placement quand vous dites que parfois vous voudrez peut-être supprimer un objet à une adresse juste calculée. ???
Destructor
@PravasiMeet Non, je veux dire quelque chose commedelete (ptr + i)
Dentranchante
39

Vous pouvez avoir plusieurs pointeurs pointant vers cette mémoire. Cela créerait un faux sentiment de sécurité si le pointeur que vous avez spécifié pour la suppression était défini sur null, mais pas tous les autres pointeurs. Un pointeur n'est rien de plus qu'une adresse, un nombre. Cela pourrait aussi bien être un int avec une opération de déréférencement. Mon point est que vous devriez également analyser chaque pointeur pour trouver ceux qui font référence à la même mémoire que vous venez de supprimer, et les annuler également. Il serait intense en calcul d'analyser tous les pointeurs de cette adresse et de les annuler, car le langage n'est pas conçu pour cela. (Bien que certains autres langages structurent leurs références pour atteindre un objectif similaire d'une manière différente.)

AaronLS
la source
19

Un pointeur peut être enregistré dans plusieurs variables, la définition de l'une de celles-ci sur NULL laisserait toujours des pointeurs invalides dans les autres variables. Donc, vous ne gagnez pas vraiment beaucoup, vous créez plus probablement un faux sentiment de sécurité.

En plus de cela, vous pouvez créer votre propre fonction qui fait ce que vous voulez:

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}
qc
la source
12

Parce qu'il n'est pas vraiment nécessaire de le faire, et parce que cela nécessiterait de supprimer en prenant un pointeur vers un pointeur plutôt qu'un simple pointeur.

snemarch
la source
vrai, mais cela entraînerait les mêmes frais généraux
snemarch
7

deleteest principalement utilisé dans les destructeurs, auquel cas la définition d'un membre sur NULL est inutile. Quelques lignes plus tard, à la clôture }, le membre n'existe plus. Dans les opérateurs d'affectation, une suppression est généralement suivie d'une affectation de toute façon.

En outre, cela rendrait le code suivant illégal:

T* const foo = new T;
delete foo;
MSalters
la source
6

Voici une autre raison; Supposons que la suppression définisse son argument sur NULL:

int *foo = new int;
int *bar = foo;
delete foo;

La barre doit-elle être définie sur NULL? Pouvez-vous généraliser cela?

SingleNegationElimination
la source
5

Si vous avez un tableau de pointeurs et que votre deuxième action consiste à supprimer le tableau vide, il n'y a aucun point à définir chaque valeur sur null lorsque la mémoire est sur le point d'être libérée. Si vous voulez qu'il soit nul ... écrivez-lui null :)

Compte mort
la source
4

C ++ vous permet de définir votre propre opérateur new et delete afin que, par exemple, ils utilisent votre propre allocateur de pool. Si vous faites cela, il est possible d'utiliser new et delete avec des choses qui ne sont pas strictement des adresses mais disent des index dans votre tableau de pool. Dans ce contexte, la valeur de NULL (0) peut avoir une signification juridique (faisant référence au premier élément du pool).
Ainsi, le fait de définir automatiquement NULL sur son argument n'a pas toujours la signification de - définir la valeur sur une valeur non valide. La valeur non valide peut ne pas toujours être NULL.

shoosh
la source
4

La philosophie de C ++ est "ne payez que si vous l'utilisez". Je pense que cela peut répondre à votre question.

Parfois aussi, vous pouvez avoir votre propre tas qui récupérera la mémoire supprimée .. ou parfois un pointeur n'appartenant à aucune variable. Ou pointeur stocké dans quelques variables - il est possible de ne mettre à zéro qu'une seule d'entre elles.
Comme vous pouvez le voir, il y a de nombreux problèmes et problèmes possibles.

bayda
la source
3

Définir automatiquement le pointeur sur NULL ne résoudrait pas la plupart des problèmes liés à une mauvaise utilisation du pointeur. Le seul crash qu'il éviterait est si vous essayez de le supprimer deux fois. Que faire si vous appelez une fonction membre sur un tel pointeur? Il planterait toujours (en supposant qu'il accède aux variables membres). C ++ ne vous empêche pas d'appeler une fonction sur des pointeurs NULL, et ne devrait pas non plus le faire du point de vue des performances.


la source
-1

Je vois des gens donner des réponses étranges à cette question.

ptr = NULL; Comment une déclaration aussi simple peut-elle retarder les performances?

Une autre réponse est que nous pouvons avoir plusieurs pointeurs pointant vers le même emplacement mémoire. Sûrement nous pouvons. Dans ce cas, l'opération de suppression sur un pointeur rendrait uniquement ce pointeur NULL (si la suppression rendait le pointeur NULL) et l'autre pointeur serait non NULL et pointant vers l'emplacement mémoire qui est libre.

La solution pour cela aurait dû être que l'utilisateur devrait supprimer tous les pointeurs pointant vers le même emplacement. En interne, il devrait vérifier si la mémoire est déjà libérée plutôt que de ne pas la libérer. Ne rendez le pointeur NULL.

Stroustrup aurait pu concevoir la suppression pour fonctionner de cette manière. Il pensait que les programmeurs s'en chargeraient. Alors il a ignoré.

Nimesh Bapodra
la source