Problemas exclusão de uma matriz dinâmica 2D em C ++ (que é, eventualmente, loja num vector)

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

Pergunta

Então, eu tenho essa matriz dinâmica 2d qual o conteúdo que eu quero para libertar quando eu estou feito com ele. No entanto, eu continuo correndo em uma corrupção de memória após o processo de destruição. O código fina funciona (claro que com vazamentos de memória) se eu comentar o destruidor. (Visual Studio 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;    
} 

Eu não tenho idéia o que está errado com o código. A única outra coisa é em outro lugar, eu fiz isso em um loop onde o acidente ocorreu

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

Este não deve ser causar qualquer problema, certo? Se eu me lembro correta, push_back faz uma cópia em vez de armazenar um ponteiro ou uma referência.

PS. Sim, eu deveria usar vetores. Mas eu não estou autorizado a.

Informações adicionais:

O operador = e construtor de cópia não estão definidos. Eu acho que é uma razão para o problema.

Foi útil?

Solução

Seu problema é que você adivinhou aqui:

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

O vector faz cópias dos elementos que você empurre. O que você tem para o seu construtor de cópia e / ou operator= para sua classe? Se você tiver nenhuma definida, a versão padrão que o compilador cria para você simplesmente faz cópias dos membros de sua classe. Isso irá copiar a membros ponteiro red, green e blue para a nova instância. Em seguida, a instância antiga que você copiou será destruído quando ele sai do escopo, fazendo com que os ponteiros para ser excluído. O que você copiado para o vector terá então ponteiros inválidos desde o alvo do ponteiro é, assim, eliminado.

Uma boa regra de ouro é que se você tiver quaisquer membros ponteiro bruto, então você precisa fazer um construtor de cópia e operator= que irá lidar com esta situação corretamente, certificando-se que os ponteiros são dadas novos valores e não compartilhada, ou que a propriedade é transferida entre as instâncias.

Por exemplo, a classe std::auto_ptr tem um ponteiro bruto -. A semântica do construtor de cópia é para transferir a propriedade do ponteiro para o alvo

A classe boost::shared_ptr tem um ponteiro bruto - a semântica é a titularidade de ações por meio de contagem de referência. Esta é uma boa maneira de std::vectors punho contendo ponteiros para sua classe -. Os ponteiros compartilhados irá controlar a propriedade para você

Outra forma seria usar vetores para tomar o lugar de seus ponteiros membros -. Os ponteiros membros são simplesmente aliases para suas matrizes de qualquer maneira, de modo que o vector é um bom substituto

Outras dicas

A menos que você tem um construtor de cópia profunda e operador de atribuição para a classe FrameData minha intuição é que o compilador gera um construtor de cópia para usar com push_back. construtores de cópia gerados automaticamente e operadores de atribuição irá fazer uma cópia memberwise, o que resultará em uma cópia superficial neste caso. Infelizmente o seu destruidor não sabe sobre a cópia de modo durante a cópia, há uma boa chance de que uma cópia temporária do FrameData é destruído e que terá todos os seus dados com ele.

Chamando o destruidor novamente no final do processo resultará em um duplo livre, além de outras atribuições pode ter utilizado parte da memória "livre". Que se parece com um bom motivo para corrupção de pilha a partir daqui.

A melhor maneira de encontrar problemas como estes é, geralmente, para usar uma ferramenta como valgrind ou Purify para localizar o problema.

Esta não é uma resposta à sua pergunta , apenas uma observação.

Uma vez que seu quadro de dados pode ser grande, para evitar a cópia excessiva, pode ser que é melhor para você usar

std::vector<FrameData *> frames;

EDIT: Como outros apontaram, isso também vai resolver seu problema deixar de funcionar.

Você está correto sobre push_back fazer uma cópia, mas não FrameData ter uma cópia construtor e atribuição operador adequado?

Além disso, por que o elenco aqui:

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

Em C ++, se você tem que usar um elenco C-estilo (ou reinterpretar), o código é quase certamente errado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top