2009-11-07 11 views
0

J'essaie d'utiliser priority_queue, et le programme échoue constamment avec le message d'erreur HEAP CORRUPTION DETECTED.Problème avec priority_queue - Ecriture de mémoire après tas

voici les extraits:

class CQueue { ... 
       priority_queue<Message, deque<Message>, less<deque<Message>::value_type> > m_messages; 
...}; 

message de classe a surchargées opérateurs> et <

Ici je remplis la file d'attente:

CQueue & operator+=(Message &rhv) 
{ 
    m_messages.push(rhv); //This is where program fails 
    return *this; 
} 

et dans le programme principal:

string str; 
CQueue pq; 
for(int i = 0; i < 12; ++i) 
{ 
    cin >> str; 

    Message p(str.c_str(), rand()%12); //Create message with random priority 
    pq += p;       //add it to queue 
} 

Je n'ai aucune idée de ce qui semble être le problème. Il arrive quand je pousse sur 8 articles, et il échoue sur la ligne

push_heap(c.begin(), c.end(), comp); 

dans < file>

:(

Voici la définition de classe de message - il est très simple:

#pragma once 

#include <iostream> 
#include <cstring> 
#include <utility> 

using namespace std; 

class Poruka 
{ 
private: 
char *m_tekst; 
int m_prioritet; 
public: 
Poruka():m_tekst(NULL), m_prioritet(-1){} 

Poruka(const char* tekst, const int prioritet) 
{ 
    if(NULL != tekst) 
    { 
    // try{ 
      m_tekst = new char[strlen(tekst) + 1]; 
     //} 
     //catch(bad_alloc&) 
    // { 
    //  throw; 
    // } 


     strcpy(m_tekst, tekst); 
    } 
    else 
    { 
    // try 
    // { 
      m_tekst = new char[1]; 
    // } 
    // catch(bad_alloc&) 
    // { 
    //  throw; 
    // } 

     m_tekst[0] = '\0'; 
    } 
    m_prioritet = prioritet; 
} 

Poruka(const Poruka &p) 
{ 
    if(p.m_tekst != NULL) 
    { 
     //try 
     //{ 
      m_tekst = new char[strlen(p.m_tekst) + 1]; 
     //} 
     //catch(bad_alloc&) 
     //{ 
     // throw; 
     //} 

     strcpy(m_tekst, p.m_tekst); 
    } 
    else 
    { 
     m_tekst = NULL; 
    } 
    m_prioritet = p.m_prioritet; 
} 

~Poruka() 
{ 
     delete [] m_tekst; 
} 

Poruka& operator=(const Poruka& rhv) 
{ 
    if(&rhv != this) 
    { 
     if(m_tekst != NULL) 
      delete [] m_tekst; 

    // try 
     //{ 
      m_tekst = new char[strlen(rhv.m_tekst + 1)]; 
     //} 
     //catch(bad_alloc&) 
     //{ 
     // throw; 
     //} 

     strcpy(m_tekst, rhv.m_tekst); 
     m_prioritet = rhv.m_prioritet; 
    } 
    return *this; 
} 

friend ostream& operator<<(ostream& it, const Poruka &p) 
{ 
    it << '[' << p.m_tekst << ']' << p.m_prioritet; 
    return it; 
} 

//Relacioni operatori 

friend inline bool operator<(const Poruka& p1, const Poruka& p2) 
{ 
    return p1.m_prioritet < p2.m_prioritet; 
} 

friend inline bool operator>(const Poruka& p1, const Poruka& p2) 
{ 
    return p2 < p1; 
} 

friend inline bool operator>=(const Poruka& p1, const Poruka& p2) 
{ 
    return !(p1 < p2); 
} 

friend inline bool operator<=(const Poruka& p1, const Poruka& p2) 
{ 
    return !(p1 > p2); 
} 

friend inline bool operator==(const Poruka& p1, const Poruka& p2) 
{ 
    return (!(p1 < p2) && !(p2 < p1)); 
} 

friend inline bool operator!=(const Poruka& p1, const Poruka& p2) 
{ 
    return (p1 < p2) || (p2 < p1); 
} 

};

Poruka - message

+3

Si vous allez utiliser 'l'aide std' d'espace de noms, ne nommez pas votre propres classes les mêmes choses que les classes dans 'namespace std' (cf' queue'). –

+0

pouvez-vous ajouter la définition de classe de message? – Naveen

+0

La réponse d'Adam semble bonne, mais nous ne pouvons pas être sûrs qu'il a raison, sauf si vous publiez la définition complète du message. – jmucchiello

Répondre

3

Je pense que le problème est que vos objets Message conservent des pointeurs vers des chaînes C brutes qui sont ensuite désallouées. Dans ces lignes:

cin >> str; 

Message p(str.c_str(), rand()%12); 

A chaque itération de la boucle, vous lisez dans une nouvelle valeur à str, qui annule tous les anciens pointeurs retournés par sa méthode c_str(), de sorte que vos messages plus anciens pointent vers des données non valides. Vous devez modifier votre objet Message afin qu'il stocke sa chaîne en tant que std::string au lieu d'un char*. Cela copiera correctement la chaîne dans l'objet Message. Sinon, si vous ne pouvez pas modifier la classe Message, vous devrez copier explicitement la chaîne, par ex. en utilisant strdup() ou malloc()/new[] + strcpy(), puis vous devez vous rappeler de libérer les copies de la chaîne à un moment ultérieur.

+1

Non. Ce n'est pas vrai, il copie correctement les chaînes brutes (ce qui m'a surpris) –

+0

@Martin York: J'ai posté ma réponse avant de poster la définition de la classe Message, donc je devinais seulement qu'il n'a pas copié la chaîne, mais il semble qu'il a réussi à trouver le problème. –

1

Je n'arrive pas à l'échouer.
Mais il n'y a pas assez d'informations pour compiler cette ligne:

push_heap(c.begin(), c.end(), comp); 

Mais les seuls problèmes que je vois sont:

1) Vous avez un constructeur par défaut qui pourrait créer un Poruka avec un nom NULL:

Poruka::Poruka():m_tekst(NULL), m_prioritet(-1){} 

2) Pas un problème parce que vous tester pour elle la plupart des endroits, mais dans l'opérateur d'affectation vous manquez un test:

Poruka::Poruka& operator=(const Poruka& rhv) 
{ 
.... 
    // There was no test for 'rhv.m_tekst' being NULL here. 
    // 
    m_tekst = new char[strlen(rhv.m_tekst + 1)]; 
    strcpy(m_tekst, rhv.m_tekst); 

Notes:

  • Vous pouvez rendre votre code beaucoup plus simple en utilisant la classe std :: string.
  • Si vous voulez toujours utiliser char * alors si vous le faites, il n'est jamais NULL alors le code est plus simple
  • Il existe également un modèle plus simple pour définir le constructeur de copie standard et l'opérateur d'affectation. Il est appelé l'idium de copie/échange.
  • Vous n'avez pas besoin de définir tous ces opérateurs relationnels. Il y a un ensemble de modèles qui fonctionnent automatiquement dans http://www.sgi.com/tech/stl/operators.html. Vous avez juste besoin de définir l'opérateur et l'opérateur == <

Voici un exemple de la copie/swap idium

class X 
{ 
    X(X const& copy) 
    { 
      // Do the work of copying the object 
      m_tekst  = new char[strlen(copy.m_tekst) + 1]; 
      ... 
      m_prioritet = copy.m_prioritet; 
    } 
    X& operator=(X const& copy) 
    { 
     // I like the explicit copy as it is easier to read 
     // than the implicit copy used by some people (not mentioning names litb) 
     // 
     X tmp(copy); // Use the copy constructor to do the work 

     swap(tmp); 
    } 
    void swap(X& rhs) throws() 
    { 
     std::swap(this->m_tekst, rhs.m_tekst); 
     std::swap(this->prioritet, rhs.prioritet); 
    }