2013-10-04 3 views
0

J'ai un std::map où j'enregistrer un pointeur vers une classe. Dans le constructeur de la classe, plusieurs valeurs sont passées, de sorte que les variables de la classe ont une valeur réelle. Mon problème ici est que le mot-clé this crée une erreur de segmentation lorsque j'appelle une fonction de cette classe qui utilise l'une des variables précédemment définies. Cela ressemble à cela en détail (version courte):"this" mot-clé provoque une erreur de segmentation

Command::Command(const char *name, commandHandler h) // commandHandler is a function pointer 
{ 
    this->name = name; 
    this->handler = h; 
} 

Command::execute(int cn, std::vector<char *> args) 
{ 
    if (this->handler != NULL) // "this" is according to gdb a pointer to a class Command at 0x0 
     (handler)(cn, args); 
} 

La carte est dans une classe statique, les éléments cartographiques sont insérés dans une fonction statique.

Edit: En raison des commentaires et réponses (gars merci): j'ajouter le pointeur à la classe dans une registerCommands de fonction() qui crée essentiellement des pointeurs à l'aide Command *command_xxx = new Command("xxx", &(handler_func)); et met que dans une carte dans une classe statique. L'appel provient d'une autre méthode de la même classe que la carte et de la fonction registerCommands(). Le pointeur de classe est obtenu en utilisant commands.find("xxx")->second; qui renvoie null -> null pointeur.

+0

Afficher le numéro – Kal

+0

Selon le contexte, le problème exact ne peut pas être déterminé. En fonction de la description, l'objet sur lequel vous voulez appeler la fonction est perdu ou vous fournissez un pointeur amusant (par exemple, un pointeur nul) lors de l'appel de la fonction membre. –

Répondre

2

Le pointeur de la classe est obtenue en utilisant commands.find("xxx")->second; qui renvoie null -> null pointeur.

Et puis, lorsque vous faites commands.find("xxx")->second->execute(...), vous obtenez un segfault. Il y a (au moins) deux choses qui ne vont pas ici.

L'un est le ->execute(...) sans vérifier si l'élément trouvé est non nul. Vous appelez un comportement indéfini si l'élément trouvé est null. Ce qui se passe avec la plupart des systèmes dépend si oui ou non execute() est une fonction virtuelle. Si c'est virtuel, vous allez avoir une erreur de segfault ou de bus avant l'appel. Si elle n'est pas virtuelle, la machine sous-jacente sait exactement quelle fonction appeler. La segfault se produira à l'intérieur de la fonction execute() lorsque vous essayez d'accéder à un membre de données. Vous devez savoir qu'un pointeur n'est pas nul ou vérifier s'il est avant d'envoyer un appel d'objet. Une fois que vous faites ->execute(), c'est fini, d'une façon ou d'une autre. L'autre problème est le ->second. Et si "xxx" n'est pas sur la carte? Si ce n'est pas le cas, commands.find("xxx") renverra commands.end() et fonctionnera sur ce comportement indéfini. Tout ce que vous devriez faire avec l'itérateur final est de tester que vous ne l'avez pas touché.

C'est un peu plus bavard, mais vous devriez tester pour ces cas de coin.Vous devriez tester même si, après une analyse minutieuse, vous savez avec une confiance de 100% que votre find retournera toujours un itérateur dans les limites et que chaque itérateur dans les limites a une valeur mappée non nulle. Vous pouvez tester via des assertions, et vous pouvez éventuellement les désactiver, mais vous devriez toujours tester. Toujours.

+0

On dirait qu'il n'enregistre pas le pointeur de classe dans la carte. Merci. – user2610529

2

Cela se produit principalement lorsque vous appelez une méthode sur un pointeur défini sur NULL. Puisque this est un paramètre caché qui est passé à chaque fonction membre, GDB l'affiche comme NULL. Par exemple:

Command *command = NULL; 
command->execute(...); 
2

Vous avez un pointeur vers un endroit Command, mais le pointeur est 0. Ce pointeur est ensuite utilisé pour appeler Command::execute, ce qui signifie que la fonction membre est appelée avec this == 0.

Bien qu'il soit conforme au standard, vous pouvez très probablement essayer d'ajouter du code pour attraper cela et imprimer des informations qui pourraient aider à déboguer le problème:

if(!this) print_backtrace(); 

ou quelque chose de similaire. (Pour une rétrospection sur Linux, voir this answer j'ai donné il y a peu de temps)

Questions connexes