C ++ ¿Es posible determinar si un puntero apunta a un objeto válido?

Estoy aprendiendo C ++ y leyendo C ++ Primer. Hay una pregunta que me gustaría saber la respuesta:

Dado un puntero p , ¿puedes determinar si p apunta a un objeto válido? ¿Si es así, cómo? ¿Si no, porque no?

Gracias.

No, no puedes. ¿Por qué? Porque sería costoso mantener metadatos sobre qué constituye un puntero válido y qué no, y en C ++ no paga por lo que no desea.

Y no quiere comprobar si un puntero es válido, ya que sabe de dónde viene un puntero, ya sea porque es una parte privada de su código que usted controla, o porque lo especificó en sus contratos externos.

Imposible. Piensa en este escenario.

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

Pero ptrDup aún apunta a la ubicación de la memoria apuntada por ptr que ya no existe. Entonces, la ptrDup da ptrDup resultado un comportamiento indefinido. Pero hay un recuento de referencias que es totalmente un concepto diferente.

No es realmente posible ver si un puntero es “válido” en todos sus significados.

Claro, puedes intentar desreferenciar el puntero ( *ptr = x; o x = *ptr ). Si su código no se colgó, el puntero apunta a la memoria válida. Si se estrelló, obviamente, el puntero no es bueno. Desafortunadamente, este enfoque es un poco como verificar si un arma está cargada disparándola a tu cabeza, que no es la más inteligente … Desafortunadamente, con los punteros, no hay “controlar la cámara para ver si está cargada”, por lo que no hay una buena forma de averiguar si el puntero a es válido, salvo que “si no causa un error de hardware, es válido”.

Tenga en cuenta que esto solo le dirá realmente que “el puntero apunta a algún tipo de memoria al que puede acceder” en la mayoría de los casos. NO significa que el puntero “sea correcto para lo que quiere que sea” (por ejemplo, apunta al tipo correcto). Y CIERTAMENTE no le dirá si el puntero apunta a “datos obsoletos” (es decir, cuando un puntero FUE válido, pero ahora se usa la memoria para otra cosa).

Desafortunadamente, con 2 32 o 2 64 [realmente 2 48 ] direcciones de memoria posiblemente válidas en un sistema moderno, es casi imposible saber qué direcciones son válidas y cuáles no. Incluso dentro del sistema operativo, la forma en que el sistema operativo se da cuenta si puede escribir en la memoria a la que le pidió que escribiera es “intente escribirla, vea qué sucede”. Para el sistema operativo, esto funciona bien, porque puede tener cuidado con “esto puede salir mal, y si lo hace, continuaré allí en el código de recuperación de errores”. El sistema operativo tiene que lidiar con esto porque tiene que aceptar, a) que los progtwigdores cometen errores, yb) que algunas personas realmente escriben código malicioso para TRY para romper el sistema operativo.

La forma en que una aplicación “se asegura de que los punteros sean válidos” es que el progtwigdor escribe código que es CUIDADO con lo que almacena en los punteros, cómo libera esos punteros y solo utiliza punteros que tienen valores válidos almacenados en ellos. No debe terminar “teniendo que verificar si el puntero es válido”, entonces está “haciendo las cosas mal”.

(Cuando trabajas con un sistema por un tiempo y lees los valores del puntero en un depurador, después de un tiempo reconoces punteros “buenos” y “malos”, pero eso es solo porque aprendes qué, generalmente, un buen puntero contra un El puntero malo parece. Escribir código para reconocerlo es casi imposible, especialmente si el sistema está asignando mucha memoria, por lo que usa la mayor parte del espacio disponible.

Por supuesto, en C ++, hay punteros inteligentes, vectores y varias otras herramientas que significan una gran parte del tiempo que ni siquiera tiene que preocuparse por los punteros. Pero entender cómo usar punteros y cómo funcionan los punteros sigue siendo una buena acción.

Si un puntero se establece en nullptr , eso significa que no se le ha dado un objeto al que apuntar y en su lugar se le ha asignado un valor “predeterminado”. Es posible que el puntero no se haya podido asignar a nullptr y al mismo tiempo no se le haya asignado a un objeto válido, pero en ese caso sería imposible determinarlo. Por ejemplo:

Con nullptr :

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

Sin nullptr :

 int *ptr; // using ptr while uninitialized is Undefined Behavior! if (ptr != &some_object) 

Como se indica en otras respuestas, esto no es posible con un puntero sin formato de la forma SomeObject* somePointer . Sin embargo, c++11 introdujo un nuevo conjunto de administración de memoria dinámica y nuevos punteros inteligentes . Usando un puntero inteligente puedes detectar si el recurso aún está disponible. Por ejemplo en lo siguiente:

 std::weak_ptr w; // Our pointer to a resource. { std::shared_pointer s = std::make_shared(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. 

Lea más sobre std :: shared_ptr y std :: weak_ptr para más ejemplos. Antes c++11 tipos de punteros inteligentes están disponibles en boost .