Tengo un vector que contiene un pointer para las clases:

vector<Entity*> editorElements;
vector<Entity*> entities;
vector<DirectionalLight*> dirLights;
vector<PointLight*> pointLights;
vector<SpotLight*> spotLights;

Este código está dentro de mi clase Scene. El ctor y los destructores de Scene son así:

Scene()
{
    editorElements = vector<Entity*>();
    entities = vector<Entity*>();
    dirLights = vector<DirectionalLight*>();
    pointLights = vector<PointLight*>();
    spotLights = vector<SpotLight*>();
}

~Scene()
{
    delete[] &entities;  // ERROR HERE
    delete[] &dirLights;
    delete[] &pointLights;
    delete[] &spotLights;
    delete[] &editorElements;
}

En el destructor marqué una línea ERROR HERE. No importa qué vector ponga primero, siempre obtengo el error. Es extraño, estaba funcionando bien hasta hace poco (no estaba tocando nada dentro de la clase Scene, o en ninguna otra clase que use una instancia de Scene) y de repente provocó una excepción:

enter image description here

No importa si las vector s están vacías o tienen elementos, da el error de todos modos.

Necesito asistencia para solucionar esto.

c++
-1
agiro 8 sep. 2018 a las 14:16

3 respuestas

La mejor respuesta

La eliminar expresión delete [] x se describe así:

Destruye una matriz creada por una nueva expresión []

Entonces delete[] &entities solo tiene sentido si &entities es una matriz creada por una expresión new[]. ¿Derecha?

Pero entities es un std::vector<Entity*>, no un Entity[]. No lo creó con new[], por lo que no debe eliminarlo con delete[].

std::vector no es azúcar sintáctico para una matriz, es una clase de plantilla, y std::vector<Entity*> entities no es una matriz, es un objeto con un constructor y destructor. Eso también nos dice que esta afirmación

entities = vector<Entity*>();

No hace nada útil: entities es un objeto, por lo que ya se construyó por defecto. Simplemente está construyendo por defecto un temporal anónimo del mismo tipo y asignándolo.

Finalmente, almacenar punteros en bruto en un vector está bien aquí, ya que el vector no es responsable de la vida útil de los objetos. En la mayoría de las situaciones, es preferible que el vector sea el propietario de los objetos para que no tenga que preocuparse por eliminarlos manualmente, ya sea directamente con

vector<Entity>

O indirectamente con

vector<unique_ptr<Entity>>

NÓTESE BIEN. una buena pauta es: no debe usar new, new[], delete o delete[] en absoluto en el código de usuario.

Use un objeto de clase para administrar su almacenamiento, porque el compilador se encargará de llamar a sus constructores y destructores por usted.

Si necesita una clase personalizada, escriba una que solo administre la memoria, de modo que permanezca desacoplada de la lógica de su programa. De lo contrario, solo use las instalaciones de la biblioteca estándar como std::vector, std::array, std::unique_ptr, std::shared_ptr si realmente necesita ese modelo de propiedad, etc.

2
Useless 8 sep. 2018 a las 11:53

Los vectores no son punteros nuevos, y mucho menos matrices nuevas. Entonces no deberías eliminarlos. Si necesita llamar a eliminar en los punteros almacenados en los vectores, debe recorrer los vectores y eliminar cada elemento. Pero es mejor que guarde los punteros inteligentes en su lugar (por ejemplo, std::unique_ptr<Entity>. Eso es si necesita almacenar punteros en objetos asignados dinámicamente.

Tenga en cuenta que si termina eliminando elementos en el destructor, también deberá ocuparse de regla de tres / cinco.

2
juanchopanza 8 sep. 2018 a las 11:33

de repente planteó una excepción

Es por tratar de eliminar algo que no deberías eliminar. La sintaxis delete[] es para la eliminación de una asignación dinámica matriz . Pero le proporciona un puntero a una std::vector. Entonces, el compilador toma esta dirección para la eliminación como si fuera una matriz, lo que incluye averiguar su tamaño y luego eliminar todo el segmento. Pero no existe una figura tan apropiada, ya que no se trata de una matriz, por lo que en tiempo de ejecución terminas tratando de eliminar algo en un lugar al que no tienes permiso de acceso y, por lo tanto, obtienes el error de aserción, ya que este es un acceso violación, también conocido como segfault.

Además, vector es una clase que administra su propia memoria. Si desea liberar entidades contenidas dentro de este contenedor, es decir, los elementos individuales asignados dinámicamente, entonces debe recorrerlos y eliminar cada uno. Convenientemente, por ejemplo, usando auto y a basado en rango para bucle de esta manera:

for (auto ptr : entities)
    delete ptr;

Pero, en la mayoría de los escenarios, es mejor que ahorre esta sobrecarga de administración de memoria y opte por { {X0}} en lugar de los punteros sin formato:

#include <memory>
...
std::vector<std::unique_ptr<Entity>> entities;

De esta manera, no tiene que preocuparse por liberar memoria, ya que será liberada por std:: unique_ptr una vez que sea destruida, como parte de la destrucción de vector.

Además, esto es innecesario y probablemente no sea lo que pretendía hacer:

entities = vector<Entity*>();

Como el objeto vector en sí mismo ya está definido (por lo que existe) antes de esta línea, y todo lo que hace es crear uno nuevo idéntico y asignarlo a entities.

1
Geezer 8 sep. 2018 a las 18:21