2010-01-06 17 views
6

Tengo un abstractBase clase y Derived clase.¿Eliminar operador y matrices?

int main() 
{ 
    Base *arrayPtr[3]; 

    for (int i = 0; i < 3; i++) 
    { 
    arrayPtr[i] = new Derived(); 
    } 

    //some functions here 

    delete[] arrayPtr; 

    return 0; 
} 

No estoy seguro de cómo usar el operador de eliminación. Si elimino una matriz de punteros de clase base como se muestra arriba, ¿esta llamada derivará los objetos de la clase destructores y limpiará la memoria?

Respuesta

10

Tienes que iterar sobre los elementos de la matriz, delete cada uno de ellos. Luego llame al delete [] en la matriz si se ha asignado dinámicamente usando new[].

En su código de ejemplo, la matriz se asigna en la pila por lo que no debe llamar al delete [].

También asegúrese de que su clase Base tenga un destructor virtual.

Referencia: When should my destructor be virtual.

+0

+1 para el punto destructor 'virtual' –

+7

No es necesario llamar a delete [] en la matriz, si no se ha 'renovado'. – fretje

+0

sí Estaba editando mi respuesta cuando escribió su comentario, thx –

10

No, usted tiene que eliminar explícitamente cada elemento de la matriz:

for (int i = 0; i < 3; ++i) 
{ 
    delete arrayPtr[i]; 
} 
+0

@Roger No veo eliminar [] –

+0

@Roger: me di cuenta de que después de mi primera publicación ... ya estaba editado, pero gracias de todos modos;) – fretje

+0

James: Fue editado en los primeros 5 minutos. –

2

su lugar, debe hacer:

for (int = i; i < 3; i++) 
{ 
    delete arrayPtr[i]; 
} 

Y usted no debe hacer delete[] arrayPtr; como usted está tratando de libre/borrar una pila asignado arrayPtr.

Otra cosa a considerar es utilizar un std::vector de punteros en lugar de una matriz. Y si está utilizando un compilador que implementa TR1, también podría usar un std::vector de std::tr1::shared_ptr en lugar de punteros sin procesar, y entonces no tendría que preocuparse por eliminar esos objetos usted mismo.

Ejemplo:

{ 
    std::vector< std::tr1::shared_ptr<Base> > objects; 
    for (int i=0; i < 3; ++i) 
    { 
     objects.push_back(std::tr1::shared_ptr<Base>(new Derived())); 
    } 
} // here, once "objects" exit scope, all of your Derived objects are nicely deleted 
+0

¡Shared_ptr <> no es la respuesta a todo! El puntero no se comparte para empezar. boost :: ptr_vector <> puede ser una mejor opción. –

+0

Estoy de acuerdo, solo estaba sugiriendo "el menor de los males", en cierto sentido, que ya he compartido_ptr en mi macbook con gcc, y para usar boost :: ptr_vector necesitaría arrastrar boost en el proyecto, lo que podría no ser necesario . – Dmitry

+0

@Martin York: 'shared_ptr <>' no es * la * respuesta para todo, pero es * una respuesta * segura para la mayoría de las preguntas del puntero. Generalmente lo uso a menos que tenga un motivo para usar algo diferente, y me siento razonablemente cómodo sugiriéndolo en situaciones generales. –

0

Asegúrese Base tiene un destructor virtual. Luego, como fretje outlined, elimine cada elemento de la matriz y luego elimine la matriz.

Debe utilizar std::vector para la matriz. Dicho esto, debería realmente utilizar un contenedor hecho para este tipo de cosas. (Por lo tanto, no se puede eliminar accidentalmente todos los elementos, lo que sin duda será el caso si se lanza una excepción). Boost tiene such a library.

+0

Aunque "deberías usar contenedores" es definitivamente un buen consejo, de alguna manera no debería lanzarse demasiado rápido. Quiero decir 1) entiendo qué está sucediendo al hacerlo a mano, luego 2) en el código de producción aprovechar bibliotecas sólidas como STL y Boost. De lo contrario, ¿no hay una tendencia a considerar los contenedores y otras herramientas proporcionadas por las bibliotecas como solo cajas negras? ¿Qué piensas? –

+0

Gregory: En desacuerdo. En algún momento debe comprender lo que sucede bajo el capó (tal vez), pero ya no está claro para mí en qué orden debería ser (yo solía estar de acuerdo con usted). ¿Debería entender cómo funciona malloc antes de poder llamar a algo nuevo? ¿Debería entender cómo funcionan los vtables antes de usar dynamic_cast (y * luego * descubrir que no es una parte garantizada de la implementación)? Ambos no Dicho esto, siempre debe saber a dónde ir para buscar la información que necesita, o con quién hablar, etc. –

+0

@Roger Entiendo su punto. Tomando sus ejemplos, no necesita conocer los detalles de implementación de las asignaciones de la memoria del montón, sin embargo, es bueno saber la diferencia entre el montón y la pila. No es necesario que sepa cómo se implementa vtable y eso, aún debe saber que llamar a un método virtual genera una indirección. Finalmente, los algoritmos y las estructuras de datos son oro: definitivamente debe saber la diferencia entre una matriz contigua y una lista de conceptos, aunque esté utilizando implementaciones std :: vector o std :: list; De lo contrario, a la larga solo te faltan pistas :) –

1

Debe eliminar los miembros de la matriz individualmente. También debe asegurarse de que su clase base tenga un destructor virtual. También es posible que desee considerar hacer una matriz (o mejor aún un std :: vector) de punteros inteligentes, como boost :: shared_ptr.

1

No, no puedes hacer eso. Como otros sugirieron que tienes que revisar cada elemento y eliminarlo. Es una regla muy simple para recordar. Si se distribuyen utilizando new a continuación, utilizar delete, y si se hubiera usado new[] a continuación, utilizar delete[]

0

No, esto no es hacer lo que quiera.

Hay dos puntos a tener en cuenta aquí:

  1. la sintaxis delete[] arrayPtr se utiliza si asigna dinámicamente la matriz, así:

    arrayPtr = new (Base *)[mylength]; 
    

    En su caso, sin embargo, tener una matriz estáticamente asignada, por lo que no hay necesidad de eliminarla. Usted, sin embargo, tiene que eliminar los elementos individuales de la matriz:

    for (int = i; i < 3; i++) 
        delete arrayPtr[i]; 
    
  2. El segundo punto es necesario cuidar es hacer que el destructor de la clase Base virtual:

    class Base 
    { 
        virtual ~Base(); 
        /* ... */ 
    }; 
    

    Esto garantiza que cuando se invoca delete en un Base * que apunta a un Derived, se llama al destructor de Derived, no solo al destructor de Base.

1

Aviso lo que está ausente:

int main() { 
    boost::ptr_vector<Base> v; 
    for (int i = 0; i < 3; i++) v.push_back(new Derived()); 
    // some functions here, using v[0] through v[2] 
} 

Comprobar Boost's pointer containers a cabo.

1

La eliminación del operador debe coincidir con el operador nuevo en ese puntero, si fue asignado con new[], debe llamar al delete[] y viceversa;

int* pInt = new int; 
delete pInt; OK 
delete [] pInt; WRONG 

int[] pIntArr = new int[3]; 
delete [] pIntArr; OK 
delete pIntArr; WRONG 

En su caso hay algo más malo - que están tratando de delete que fue asignado en la pila. Eso no funcionaria

Debe borrar cada puntero de forma individual en este caso particular.

1

Lo que tienes allí es un comportamiento indefinido, un error. Cada llamada al new debe coincidir con un delete; cada llamada a new[] debe coincidir con un delete[]. Los dos están separados y no se pueden mezclar.

En el código que ha publicado, tiene una serie de punteros a Base asignados en la pila. Entonces llama al delete[] en una matriz asignada en la pila; no puede hacer eso. Solo puede delete[] una matriz asignada en el montón con new[].

Necesita una llamada al delete para cada elemento asignado con new - o preferiblemente, investigue utilizando una clase de contenedor, como std::vector, en lugar de usar una matriz.

0

Está mezclando paradigmas: el operador de eliminación de matriz está diseñado para liberar memoria asignada por el nuevo operador de matriz, pero está asignando su matriz a la pila como una matriz de punteros y luego asignando un objeto para cada matriz miembro. En su código, necesita iterar a través de la matriz.

Para utilizar la matriz del nuevo operador, que le declara así:

Base *array; 
array = new Base[3]; 
/* do stuff */ 
delete[] array; 

Esto asigna un área de memoria contigua para los tres objetos - en cuenta que tienes una gran variedad de objetos de la base, no una matriz de punteros a los objetos Base.