2009-10-31 9 views
2

J'essayais d'utiliser une liste STL en C++ et je suis arrivé dans une étrange exception que je ne suis pas capable de comprendre. La liste est définie comme list<ASTNode*> m_stats; et ASTNode* est une classe. Lorsque je tente d'ajouter des éléments en appelantSTL liste exception

ASTNode *node = new ASTNode(); 
m_stats.push_back(node); 

il jette l'exception suivante:

Program received signal EXC_BAD_ACCESS, Could not access memory. 
Reason: KERN_PROTECTION_FAILURE at address: 0x00000004 
0x91c20fe7 in std::_List_node_base::hook() 

J'ai essayé de déboguer avec gdb et la valeur inspectée insérée, est-il pas nul et il est exactement ce qu'il faut être ..

l'est backtrace:

#0 0x91c20fe7 in std::_List_node_base::hook() 
#1 0x0000a9fb in std::list<ASTNode*, std::allocator<ASTNode*> >::_M_insert (this=0x180344, __position={_M_node = 0x0}, [email protected]) at stl_list.h:1152 
#2 0x0000aa27 in std::list<ASTNode*, std::allocator<ASTNode*> >::push_front (this=0x180344, [email protected]) at stl_list.h:743 
#3 0x0000aa45 in ASTStatements::addStatement (this=0x180340, stat=0x180410) at ast.h:277 

Suis-je manque quelque chose?

EDIT: source de classe ajouté

class ASTStatements : public ASTNode 
{ 
list<ASTNode*> m_stats; 

public: 
    ASTStatements() {} 

    ASTStatements(list<ASTNode*> stats) 
    { 
     std::copy(stats.begin(), stats.end(), m_stats.begin()); 
    } 

    ASTStatements(const ASTStatements &other) 
    { 
     std::copy(other.m_stats.begin(), other.m_stats.end(), m_stats.begin()); 
    } 

    ASTStatements &operator= (const ASTStatements &other) 
    { 
     if (&other != this) 
     { 
      std::copy(other.m_stats.begin(), other.m_stats.end(), m_stats.begin()); 
     } 
    } 

    ASTStatements *clone() 
    { 
      return new ASTStatements(*this); 
     } 

     u8 type() 
     { 
      return 0; 
     } 

     const char *generateASM() 
     { 
      list<ASTNode*>::iterator it = m_stats.begin(); 

      while (it != m_stats.end()) 
      { 
       ((ASTNode*)*it)->generateASM(); 
       ++it; 
      } 
     } 

     void addStatement(ASTNode *stat) 
     { 
      m_stats.push_front(stat); 
     } 

     u8 typeCheck() 
     { 
      return 0; 
     } 
}; 

Je l'ai utilisé dans un fichier de grammaire de bison à gérer plusieurs déclarations (n'a pas trouvé une meilleure façon de gérer une liste générique d'éléments dans un terminal non) dans cette chemin:

statements: 
    statement { if ($$ == null) $$ = new ASTStatements(); ((ASTStatements*)$$)->addStatement($1); } statements { $$->generateASM(); } 

;

Merci à l'avance

+1

Le problème ne figure dans aucune des lignes de code que vous avez publiées. Apparemment, votre 'liste' s'est corrompue quelque temps auparavant. –

+0

La trace de la pile ne correspond pas à la source publiée (push_back vs push_front, etc.) –

+1

Votre programme ne lance pas d'exception, mais votre système d'exploitation met votre programme hors de sa misère avec une erreur de segmentation. –

Répondre

4

Vos constructeurs et instructions d'affectation sont incorrects. Lorsque vous appelez std::copy, il doit déjà y avoir suffisamment d'espace à l'itérateur de destination pour accueillir tout ce que vous y copiez. La liste ne va pas grandir tout seul. Le message d'erreur que vous obtenez suggère que vous êtes en train d'écraser de la mémoire, et c'est probablement ce qui se passe exactement lorsque vous essayez de copier dans une liste qui n'est pas assez grande. (Formellement, le comportement n'est pas défini.)

Vous pouvez utiliser un std::back_insert_iterator, qui est un adaptateur d'itérateur qui ajoute des éléments au conteneur sous-jacent au lieu d'écraser l'emplacement actuel. Créer une en utilisant la fonction d'aide std::back_inserter de l'en-tête <algorithm>:

std::copy(stats.begin(), stats.end(), std::back_inserter(m_stats)); 

Mieux encore, cependant, est de sauter toute la copie et laissez propres constructeurs et opérateurs d'affectation de la liste prennent en charge pour vous, car ils sont conçu pour:

ASTStatements(list<ASTNode*> stats) 
    : m_stats(stats) 
{ } 

ASTStatements& operator=(const ASTStatements& other) 
{ 
    m_stats = other.m_stats; 
} 
+0

'ASTStatements (liste stats)' - Je ne pense pas que vous voulez passer une telle liste par copie. Que diriez-vous de 'ASTStatements (const list & stats)'?Et, vraiment, l'idiome est de passer autour des itérateurs et de les prendre comme arguments modèles: 'template ASTStatements (Début, Fin): m_stats (début, fin) {}'. Suivre des idiomes communs a ses mérites. – sbi

0

Il y avait probablement quelque chose que vous avez fait à votre liste qui a eu lieu avant que les lignes de code affiché. Je suggère de regarder tous les endroits m_stats est utilisé et vérifiez votre utilisation. Vous pouvez poster ici vos utilisations de m_stats ici et nous pourrions essayer de vous aider un peu plus.