Problemas al eliminar una matriz dinámica 2D en C++ (que eventualmente se almacena en un vector)

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

Pregunta

Entonces tengo esta matriz dinámica 2D cuyo contenido quiero liberar cuando termine.Sin embargo, sigo encontrándome con un montón de corrupción después del destructor.El código funciona bien (por supuesto, con pérdidas de memoria) si comento el destructor.(Estudio visual 2005)

FrameData::FrameData(int width, int height)
{
    width_ = width;
    height_ = height;

    linesize[0] = linesize[1] = linesize[2] = linesize[3] = 0;

    // Initialise the 2d array
    // Note: uint8_t is used by FFMPEG (typedef unsigned char uint8_t)
    red = new uint8_t* [height];
    green = new uint8_t* [height];
    blue = new uint8_t* [height];

    for (int i=0; i < height; i++)
    {
        red[i] = new uint8_t [width];
        green[i] = new uint8_t [width];
        blue[i] = new uint8_t [width];
    }       
}

FrameData::~FrameData()
{

    // Delete each column
    for (int i=0; i < height_; i++)
    {           
        delete[] ((uint8_t*) red[i]);
        delete[] ((uint8_t*)green[i]);
        delete[] ((uint8_t*)blue[i]);       
    }

    // Final cleanup
    delete[] red;
    red = NULL;

    delete[] green;
    green = NULL;

    delete[] blue;
    blue = NULL;    
} 

No tengo idea de qué está mal con el código.La única otra cosa está en otro lugar. Hice esto en un bucle donde ocurrió el bloqueo.

FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);

Esto no debería causar ningún problema, ¿verdad?Si no recuerdo mal, push_back hace una copia en lugar de almacenar un puntero o una referencia.

PD.Sí, debería usar vectores.Pero no se me permite hacerlo.

Información adicional:

El operador = y el constructor de copia no están definidos.Supongo que esa es la razón del problema.

¿Fue útil?

Solución

Tu problema es como lo adivinaste aquí:

FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);

El vector hace copias de los elementos que insertas.¿Qué tienes para tu constructor de copias y/o operator= para tu clase?Si no tiene ninguno definido, la versión predeterminada que el compilador crea para usted simplemente hace copias de los miembros de su clase.Esto copiará los miembros del puntero. red, green y blue a la nueva instancia.Luego, la instancia anterior que copió se destruirá cuando salga del alcance, lo que provocará que se eliminen los punteros.El que copió en el vector tendrá punteros no válidos ya que el objetivo del puntero se elimina.

Una buena regla general es que si tiene algún miembro puntero sin formato, entonces necesita crear un constructor de copia y operator= eso manejará esta situación correctamente, asegurándose de que los punteros reciban nuevos valores y no se compartan, o que la propiedad se transfiera entre las instancias.

Por ejemplo, el std::auto_ptr La clase tiene un puntero sin formato: la semántica del constructor de copia es transferir la propiedad del puntero al objetivo.

El boost::shared_ptr La clase tiene un puntero en bruto: la semántica es compartir la propiedad mediante el recuento de referencias.Esta es una buena manera de manejar std::vectors que contiene punteros a su clase: los punteros compartidos controlarán la propiedad por usted.

Otra forma podría ser utilizar vectores para reemplazar los punteros de miembro; de todos modos, los punteros de miembro son simplemente alias para sus matrices, por lo que el vector es un buen sustituto.

Otros consejos

A menos que tenga un constructor de copia profunda y operador de asignación para la clase FrameData mi primera impresión es que el compilador genera un constructor de copia para su uso con push_back. constructores de copia genera automáticamente y operadores de asignación va a hacer una copia miembro por miembro, lo que resultará en una copia superficial en este caso. Desgraciadamente su destructor no sabe nada de la copia por lo que durante la copia, hay una buena probabilidad de que una copia temporal de FrameData se destruye y que se llevará a todos sus datos con él.

Al llamar al destructor de nuevo más tarde en el proceso dará lugar a una doble liberación, además de otras asignaciones podría haber utilizado parte de la memoria "libre". Eso parece una buena razón para daños en el montón de aquí.

La mejor manera de encontrar problemas como estos es por lo general a utilizar una herramienta como valgrind o purificar a identificar el problema.

Esta no es una respuesta a tu pregunta., solo una observación.

Dado que los datos de su marco pueden ser grandes, para evitar una copia excesiva, puede ser mejor que use

std::vector<FrameData *> frames;

EDITAR:Como otros han señalado, esto también resolverá su problema de bloqueo.

son correctas sobre push_back hacer una copia, pero ¿FrameData tener un operador constructor de copia y la asignación adecuada?

Además, ¿por qué el elenco aquí:

delete[] ((uint8_t*) red[i]);

En C ++, si usted tiene que usar un estilo de C (o reinterpretar) fundido, el código es casi seguro que mal.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top