Problèmes suppression d'un tableau dynamique 2D en C ++ (qui est éventuellement stocker dans un vecteur)

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

Question

J'ai donc ce tableau dynamique 2d dont le contenu que je veux libérer quand je suis fait avec elle. Cependant, je continue à courir dans une corruption du tas après la destructor. Le code fonctionne très bien (bien sûr avec des fuites de mémoire) si je commente le destructor. (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;    
} 

Je ne sais pas ce qui ne va pas avec le code. La seule autre chose est ailleurs, je l'ai fait dans une boucle où la collision est survenue

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

Cela ne devrait pas être à l'origine de problème, non? Si je me souviens correcte, push_back fait une copie au lieu de stocker un pointeur ou une référence.

PS. Oui, je devrais utiliser des vecteurs. Mais je ne suis pas autorisé à.

Infos supplémentaires:

L'opérateur = et constructeur de copie ne sont pas définis. Je suppose que ce une raison pour le problème.

Était-ce utile?

La solution

Votre problème est que vous l'aurez deviné ici:

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

Le vecteur fait des copies des éléments qui vous poussent dans. Qu'avez-vous à votre constructeur de copie et / ou operator= pour votre classe? Si vous avez défini aucune, la version par défaut que le compilateur crée pour vous fait simplement des copies des membres de votre classe. Cela copiera les membres du pointeur red, green et blue à la nouvelle instance. Puis l'ancienne instance que vous avez copié sera détruit quand il est hors de portée, ce qui provoque les pointeurs à supprimer. Celui que vous avez copié dans le vecteur aura alors des pointeurs non valides puisque la cible du pointeur est ainsi supprimé.

Une bonne règle de base est que si vous avez des membres de pointeur brut, alors vous devez faire un constructeur de copie et operator= qui traitera correctement cette situation, en veillant à ce que les pointeurs sont donnés de nouvelles valeurs et non partagées, ou que la propriété est transférée entre les instances.

Par exemple, la classe std::auto_ptr a un pointeur brut -. La sémantique du constructeur de copie est de transférer la propriété du pointeur vers la cible

La classe boost::shared_ptr a un pointeur brut - la sémantique est de partager la propriété au moyen de comptage de référence. Ceci est une belle façon de gérer std::vectors contenant des pointeurs vers votre classe -. Les pointeurs partagés contrôleront la propriété pour vous

Une autre façon peut-être d'utiliser des vecteurs pour prendre la place de vos pointeurs membres -. Les pointeurs membres sont tout simplement des alias pour vos tableaux de toute façon, de sorte que le vecteur est un bon substitut

Autres conseils

Sauf si vous avez un profond constructeur de copie et opérateur d'affectation pour la classe FrameData mon sentiment est que le compilateur génère un constructeur de copie à utiliser avec push_back. Générés automatiquement les constructeurs et les opérateurs d'affectation copie feront une copie de membre à membre, ce qui entraînera une copie superficielle dans ce cas. Malheureusement, votre destructor ne connaît pas la copie si lors de la copie, il y a une bonne chance qu'une copie temporaire de FrameData est détruit et prendra toutes vos données avec.

L'appel de la destructor plus tard dans le processus se traduira par un double libre, ainsi que d'autres allocations aurait pu utiliser une partie de la mémoire « libre ». Cela ressemble à une bonne raison de la corruption du tas d'ici.

La meilleure façon de trouver des problèmes comme ceux-ci est généralement d'utiliser un outil comme valgrind ou Purifier pour identifier le problème.

Ce n'est pas une réponse à votre question , juste une observation.

Étant donné que vos données de trame pourrait être grande, pour éviter la copie excessive, peut-être il vaut mieux pour vous d'utiliser

std::vector<FrameData *> frames;

EDIT: Comme d'autres l'ont souligné, cela va aussi résoudre votre problème s'écraser.

Vous avez raison à propos push_back faire une copie, mais ne FrameData un opérateur constructeur de copie approprié et l'affectation?

En outre, pourquoi le casting ici:

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

En C ++, si vous devez utiliser un style C (ou réinterprètent) coulé, le code est presque certainement faux.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top