web-dev-qa-db-fra.com

C++ Est-il possible de déterminer si un pointeur pointe sur un objet valide?

J'apprends le C++ et lis Cimer Primer. Il y a une question que j'aimerais connaître la réponse:

Avec un pointeur p , pouvez-vous déterminer si p pointe sur un objet valide? Si c'est le cas, comment? Si non pourquoi pas

Merci.

22
2013Asker

Non, tu ne peux pas. Pourquoi? Il serait coûteux de conserver des métadonnées sur ce qui constitue un pointeur valide ou non, et en C++, vous ne payez pas pour ce que vous ne voulez pas.

Et vous ne voulez pas vérifier si un pointeur est valide, parce que vous savez d’où provient un pointeur, soit parce qu’il s’agit d’une partie privée de votre code que vous contrôlez, soit parce que vous l’avez spécifié vos contrats externes.

35
Kerrek SB

Pas possible. Pensez à ce scénario.

int *ptr = new int(10);
int *ptrDup = ptr;

delete ptr;

Mais ptrDup pointe toujours sur l’emplacement mémoire indiqué par ptr qui n’existe plus. Ainsi, le report de ptrDup entraîne un comportement non défini. Mais il existe un comptage de références qui est un concept totalement différent.

11
Mahesh

Pas vraiment possible de voir si un pointeur est "valide" dans toutes ses significations.

Bien sûr, vous pouvez essayer de déréférencer le pointeur (*ptr = x; ou x = *ptr). Si votre code ne s'est pas bloqué, le pointeur pointe vers une mémoire valide. S'il s'est écrasé, évidemment, le pointeur n'est pas bon. Malheureusement, cette approche revient un peu à vérifier si une arme est chargée en la tirant à la tête - ce qui n’est pas le plus intelligent ... Malheureusement, avec des pointeurs, il n’ya pas de "vérifier la chambre pour voir si elle est chargée", alors pas vraiment un bon moyen de savoir si le pointeur est valide, autre que "si cela ne cause pas une panne matérielle, alors c'est valide". 

Notez que cela ne vous dira vraiment que "dans la plupart des cas, le pointeur pointe vers une mémoire à laquelle vous pouvez accéder". Cela ne signifie PAS que le pointeur "est correct pour ce que vous voulez qu'il soit" (par exemple, il pointe vers le type correct). Et CERTAINEMENT ne vous dira certainement pas si le pointeur pointe sur des "données obsolètes" (c’est-à-dire quand un pointeur était valide, mais sa mémoire est maintenant utilisée pour autre chose). 

Malheureusement, avec 232 ou 264 [en fait 248Dans les systèmes modernes, il est presque impossible de savoir quelles adresses sont valides et quelles adresses ne le sont pas. Même à l'intérieur du système d'exploitation, le système d'exploitation détermine s'il peut écrire dans la mémoire à laquelle vous lui avez demandé d'écrire: "essayez de l'écrire, voyez ce qui se passe". Pour le système d'exploitation, cela fonctionne très bien, car il peut être prudent sur "cela peut mal tourner, et si c'est le cas, je continuerai là-bas dans le code de récupération d'erreur". Le système d'exploitation doit résoudre ce problème car il doit accepter, a) que les programmeurs commettent des erreurs, et b) que certaines personnes écrivent un code malveillant dans TRY pour détruire le système d'exploitation. 

Pour qu'une application "s'assure que les pointeurs sont valides", le programmeur écrit un code SENSIBLE sur ce qu'il stocke dans les pointeurs, comment il libère ces pointeurs et n'utilise que des pointeurs contenant des valeurs valides. Vous ne devriez pas finir par "avoir à vérifier si le pointeur est valide" - alors vous "le faites mal". 

(Lorsque vous travaillez avec un système pendant un certain temps et que vous lisez les valeurs d'un pointeur dans un débogueur, vous reconnaissez au bout d'un moment les pointeurs "bons" et "mauvais" - mais c'est simplement parce que vous apprenez quoi, en général, un bon pointeur Il est presque impossible d'écrire du code pour le reconnaître, en particulier si le système alloue beaucoup de mémoire et utilise donc la plus grande partie de l'espace disponible.)

Bien entendu, en C++, il existe des pointeurs intelligents, des vecteurs et divers autres outils qui signifient souvent que vous n'avez pas à vous soucier des pointeurs. Mais comprendre comment utiliser les pointeurs et leur fonctionnement reste une bonne chose à faire. 

6
Mats Petersson

Si un pointeur est défini sur nullptr, cela signifie qu'il n'a pas été attribué d'objet à désigner et qu'il a reçu une valeur "par défaut". Il est possible que le pointeur ne soit pas affecté à nullptr et en même temps ne soit pas affecté à un objet valide, mais dans ce cas, il serait impossible de le déterminer. Par exemple:

Avec nullptr:

int *ptr = nullptr;

// check if pointer is unassigned to an object
if (ptr == nullptr) ptr = new int{0};

Sans nullptr:

int *ptr;

// using ptr while uninitialized is Undefined Behavior!
if (ptr != &some_object)
4
0x499602D2

Comme indiqué dans d'autres réponses, cela n'est pas possible avec un pointeur brut de la forme SomeObject* somePointer. Cependant, c++11 a introduit un nouvel ensemble de gestion de la mémoire dynamique et de nouveaux pointeurs intelligents . En utilisant un pointeur intelligent, vous pouvez détecter si la ressource est toujours disponible. Par exemple dans ce qui suit:

std::weak_ptr<int> w; // Our pointer to a resource.
{
    std::shared_pointer<int> s = std::make_shared<int>(5); // The resource.

    w = s;       // We can set the weak pointer to the shared pointer.

    auto s2 = w; // Here we can promote the weak pointer to a shared  pointer to control 
                 // the resource.

    *s2 = 6;     // Here we can use the resource.

}                // Here the resource is destroyed.

auto s2 = w;     // Here we will fail to get the resource because it has been destroyed. We
                 // have successfully used smart pointers to detect if the resource exists.

En savoir plus sur std :: shared_ptr et std :: faible_ptr pour plus d'exemples. Avant c++11, des types équivalents de pointeurs intelligents sont disponibles dans boost .

1
Fantastic Mr Fox