Eliminar un puntero a const (T const *)

89

Tengo una pregunta básica sobre los punteros const. No puedo llamar a ninguna función miembro que no sea constante usando un puntero constante. Sin embargo, puedo hacer esto en un puntero constante:

delete p;

Esto llamará al destructor de la clase que, en esencia, es un 'método' no constante. ¿Por qué está permitido esto? ¿Es solo para apoyar esto?

delete this;

¿O hay alguna otra razón?

Naveen
fuente

Respuestas:

112

Es para apoyar:

// dynamically create object that cannot be changed
const Foo * f = new Foo;

// use const member functions here

// delete it
delete f;

Pero tenga en cuenta que el problema no se limita a los objetos creados dinámicamente:

{
 const Foo f;
 // use it
} // destructor called here

Si los destructores no se pudieran llamar en objetos const, no podríamos usar objetos const en absoluto.

Agnel Kurian
fuente
21
+1 para la última edición. Creo que esta es la verdadera razón. Llamada automática al destructor para el objeto const - casi lo mismo que delete f; donde f - puntero en const.
bayda
const Foo * fo Foo const * fno es un puntero constante para Foo. Es mejor const Foo. Foo * const f es un puntero constante a Foo.
user11373693
48

Póngalo de esta manera: si no estuviera permitido, no habría forma de eliminar objetos const sin usar const_cast.

Semánticamente, const es una indicación de que un objeto debe ser inmutable. Sin embargo, eso no implica que el objeto no deba eliminarse.

PaulJWilliams
fuente
3
Los destructores pueden mutar objetos de formas bastante violentas, por lo que este debe ser un uso extraño de la palabra 'inmutable' que no conocía anteriormente ...
DarthGizka
1
@DarthGizka no, los destructores te llevan de un estado donde hay un objeto a uno donde no lo hay. C ++ no define ningún método para observar una "mutación" después de la destrucción
Caleth
@ Caleth: es posible que el estándar no le permita mirar el objeto después de que su destructor se haya completado, pero ciertamente puede ver los efectos secundarios causados ​​por la destrucción. Por tanto, las circunstancias pueden organizarse fácilmente para hacer observable la mutación del objeto "inmutable". En los Estados Unidos, el asesinato es difícil de procesar cuando no hay un cuerpo, pero sigue siendo un asesinato (y puede haber otras pruebas suficientes para una condena). La misma diferencia.
DarthGizka
6

No puedo llamar a ninguna función miembro que no sea constante usando un puntero constante.

Sí es usted.

class Foo
{
public:
  void aNonConstMemberFunction();
};

Foo* const aConstPointer = new Foo;
aConstPointer->aNonConstMemberFunction(); // legal

const Foo* aPointerToConst = new Foo;
aPointerToConst->aNonConstMemberFunction(); // illegal

Ha confundido un puntero constante a un objeto no constante, con un puntero no constante a un objeto constante.

Una vez dicho esto,

delete aConstPointer; // legal
delete aPointerToConst; // legal

es legal eliminar cualquiera de los dos, por las razones ya indicadas en las otras respuestas aquí.

Oktalista
fuente
5

Los constructores y destructores no deben verse como "métodos". Son construcciones especiales para inicializar y derribar un objeto de una clase.

'const pointer' es para indicar que el estado del objeto no cambiará cuando se realicen operaciones en él mientras está vivo.

Indy9000
fuente
5

Otra forma de verlo: el significado preciso de un puntero constante es que no podrá realizar cambios en el objeto señalado que sería visible a través de ese o cualquier otro puntero o referencia al mismo objeto. Pero cuando un objeto se destruye, todos los demás punteros a la dirección ocupada anteriormente por el objeto ahora eliminado ya no son punteros a ese objeto . Almacenan la misma dirección, pero esa dirección ya no es la dirección de ningún objeto (de hecho, es posible que pronto se reutilice como la dirección de un objeto diferente).

Esta distinción sería más obvia si los punteros en C ++ se comportaran como referencias débiles, es decir, tan pronto como se destruye el objeto, todos los punteros existentes se establecerían inmediatamente en 0. (Ese es el tipo de cosas que se consideran demasiado costosas en tiempo de ejecución para imponerlas en todos los programas de C ++ y, de hecho, es imposible hacerlo completamente confiable).

ACTUALIZACIÓN : Leyendo esto nueve años después, es como un abogado. Ahora encuentro comprensible su reacción original. No permitir la mutación pero permitir la destrucción es claramente problemático. El contrato implícito de punteros / referencias constantes es que su existencia actuará como un bloqueo en la destrucción del objeto de destino, también conocido como recolección automática de basura.

La solución habitual a esto es utilizar casi cualquier otro idioma.

Daniel Earwicker
fuente
Si no puede destruir las cosas señaladas por punteros a const, ¿cómo lidiar con el std::unique_ptr<const T>final de su vida?
Caleth
@Caleth, entonces no habría solución para eso en C ++. Ese es solo un ejemplo del problema general: en C ++ el modificador const significa "No se puede mutar el objetivo, excepto en un sentido en el que se puede destruir por completo y hacer que todas las demás referencias sean inválidas y fuentes de comportamiento indefinido". Es por eso que creo que este tipo de pregunta debería actuar como un impulso para considerar otros idiomas. Tiene agujeros de UB que no se pueden resolver sin adoptar un enfoque básico diferente.
Daniel Earwicker