¿Por qué no puedo llamar al constructor de mi clase de una instancia de esa clase en C ++?

StackOverflow https://stackoverflow.com/questions/2146901

  •  23-09-2019
  •  | 
  •  

Pregunta

Cuando puede un objeto de una clase llamada al destructor de la clase, como si fuera una función regular? Por qué no puede llamar al constructor de la misma clase, como una de sus funciones regulares? ¿Por qué el compilador nos impide hacer esto?

Por ejemplo:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

void main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles
 objC.c() ;  // compilation error
}
¿Fue útil?

Solución

Por definición, un constructor sólo se llama una vez, cuando se crea el objeto. Si usted tiene acceso a un objeto, entonces debe haber sido creado, por lo que no está permitido llamar al constructor de nuevo - esta es la razón por la cual no se permiten llamadas a constructores explícitos. Del mismo modo, los destructores sólo deben ser llamados una vez, cuando el objeto es destruido. Si esto siempre podría hacer de forma automática, a continuación, el lenguaje también prohibiría llamadas explícitas destructor.

Sin embargo, en algunas circunstancias, es posible que desee un control preciso sobre la gestión de la memoria y la capacidad de crear y destruir objetos dentro de la memoria que está administrando de forma explícita. Para este fin, el lenguaje proporciona "la colocación de nuevo" para crear un objeto en un lugar arbitrario y destructor llamadas explícitas para destruir objetos creados de esta manera. Una llamada al constructor explícito no sería útil, ya que se necesita para ser capaz de especificar la ubicación del nuevo objeto - por lo que se obtiene "la colocación de nuevo" en su lugar. Una llamada al destructor explícito es suficiente, por lo que no hay necesidad de inventar algún tipo de juego "la colocación de eliminación".

Por lo tanto: no existe un uso válido para llamadas a constructores explícitos, por lo que no están permitidos. Hay un uso válido para llamadas explícitas destructor, por lo que son (sintácticamente) permitió, con la regla que se debe solamente nunca utilizarlos en objetos que de otra manera no será destruido, es decir, los objetos creados usando "la colocación de nuevo", y en ese caso llamarlos exactamente una vez. Su uso en cualquier otra forma, como tantos errores en C ++, compilará pero dan un comportamiento indefinido.

Otros consejos

Creo que se puede llamar explícitamente al destructor si se asegura de que la instancia se reemplaza / recreado con una llamada a la colocación de nuevo:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

int main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles
 new (&objC) c;  // placement new invokes constructor for the given memory region
}

Nunca he visto esto en la práctica, pero lógicamente debería funcionar (a menos que el constructor de C puede lanzar, en cuyo caso, me imagino, el infierno podría caerse durante el desenrollado de pila).

Sin embargo, lo que es probable que desee es sólo tarea:

objC = c();

Si el destructor tiene efectos secundarios que usted está interesado en, implementar la asignación utilizando el lenguaje de copiar y de intercambio en el que se invoca al destructor para el valor "de la izquierda".

Un destructor se debe llamar a una instancia existente de una clase - destructing la instancia es lo que hace. Un constructor crea una nueva instancia de una clase, por lo que pide a una instancia existente no tiene sentido.

Esto es similar a la forma de trabajo nuevo y de eliminación:

int * p = new int;    // call to new needs no existing instance
delete p;             // call to delete requires existing instance

Y tenga en cuenta en su código, el objeto sería destruida dos veces, una forma explícita, implícita y una vez al final de su ámbito de inclusión. Por lo general, sólo se llama explícitamente un destructor si se está haciendo algo inusual, probablemente, que implica el uso de la colocación de nuevo.

Si realmente necesita hacer algo como esto, basta con crear una función adicional y lo llaman desde el exterior y desde el propio constructor, pero vamos a ver lo que sucede cuando se necesita una llamada de este tipo:

#include<new>

class A
{
//members
};

int main()
{
//allocate buffer
char* buffer = new char[sizeof(A)];
//construct A on that memory space
A * ptrToA = ::new (buffer) A();
//destroy the object
ptrToA->~A();
//deallocate the buffer
delete[] buffer;
}

Un caso en el que se encuentra la ubicación nuevo uso es el estándar contenedores. El asignador de toma en la responsabilidad de asignar el tampón (miembro de asignar) y los objetos se construyen sobre esa tampón como se abonen en el recipiente. Por ejemplo, cuando se hace reserva en el objeto vectorial, que se reserva el espacio para N objetos significado asigna espacio para N objetos, pero no construye ellos. Entonces cuando usted push_back etc, para añadir elementos, que son creados durante ese buffer. Básicamente, se trata de una técnica para reducir la sobrecarga de repetidas llamadas a la función de asignación de memoria. Y a continuación, cuando se hace, el vector de destructor que destruiría los objetos que llaman el destructor explícita para todos los objetos en él y luego llamar al desasignar () función del asignador para liberar la memoria. Espero que esto ayude.

Trate de hacer esto:

obj.ClassName :: NombreClase (); // funciona en VC 6.0 compilador

Otra forma de pensar acerca de la restricción es que un constructor es no sólo otra función. Considere su definición: a diferencia de otras funciones, no tiene valor de retorno, y puede tener una lista de inicialización. Que sólo pasa a tener la mayor parte de la sintaxis de una función es una especie de coincidencia; realmente existe solamente con el fin de inicializar una nueva instancia de un objeto.

El constructor está allí "c ()" que se utiliza con la nueva, es decir,

c objC = new c();

Si quiere llamar a su exterior constructor de la construcción real de la instancia de clase, entonces o bien no han entendido el propósito del constructor o están tratando de poner en funcionamiento allí que no debería estar ahí.

usted está planteando un estilo particular de sintaxis más que una limitación del lenguaje. C ++ permite llamar constructor o destructor de un objeto.

c objC;
objC.~c();  // force objC's destructor to run
new(&objC); // force objC's constructor to run

¿Por qué los diseñadores del lenguaje no utilizan esta sintaxis en su lugar?

c objC;
delete(&objC) c; // force objC's destructor to run
new(&objC) c;    // force objC's constructor to run

O por qué no:

c objC
objC.~c(); // force objC's destructor to run
objC.c();  // force objC's constructor to run

Mi opinión en cuanto a por qué eligieron la sintaxis que hicieron: La primera alternativa es más flexible que el segundo. Puedo llamar al constructor / destructor en cualquier dirección y no sólo una instancia. Se necesita que la flexibilidad para la asignación, pero no para su destrucción. También parece de eliminar la primera opción de ser muy peligroso una vez destructores virtuales entrar a la confusión.

Puede invocar el constructor de la clase utilizando typeof de una instancia:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

void main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles (but is a bad idea)
 typeof objC otherObjC;  // so does this.
}

Esto no afecta el valor de la instancia objC, sino que crea una nueva instancia utilizando otherObjC constructor de la clase de objC.

Nota:. Esto puede hacer algo que no esperas si el tipo estático es una clase base del tipo dinámico de la instancia que tiene

¿Quién dice que no se puede? Sólo tienes que saber cómo.

void Foo::Bar() {
  *this = Foo(); // Reset *this
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top