2016-05-11 3 views
2

J'ai une classe qui appelle une fonction en fonction d'une valeur transmise. La fonction est vide sans paramètres et est stockée dans une carte (avec d'autres informations).Erreur de segmentation lors de l'appel de la fonction de membre lié

Le programme compile et la fonction golden_retriever fonctionne comme prévu, mais quand labrador est appelé le programme SIGSEVs avec les informations suivantes dans gdb (au-delà # 5 il est hors de la classe de test et dans le code réel):

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000000000 in ??() 
(gdb) where 
#0 0x0000000000000000 in ??() 
#1 0x000000000040dc71 in std::_Mem_fn<void (TestHandlerTwo::*)()>::operator()<, void>(TestHandlerTwo*) const (this=0x6416c0, __object=0x641400) 
    at /usr/include/c++/4.8/functional:601 
#2 0x000000000040d600 in std::_Bind<std::_Mem_fn<void (TestHandlerTwo::*)()> (TestHandlerTwo*)>::__call<void, , 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) (this=0x6416c0, 
    __args=<unknown type in /home/master/splint/SplintApp/test, CU 0x1eee, DIE 0x140c8>) 
    at /usr/include/c++/4.8/functional:1296 
#3 0x000000000040c90c in std::_Bind<std::_Mem_fn<void (TestHandlerTwo::*)()> (TestHandlerTwo*)>::operator()<, void>() (this=0x6416c0) at /usr/include/c++/4.8/functional:1355 
#4 0x000000000040bcf3 in std::_Function_handler<void(), std::_Bind<std::_Mem_fn<void (TestHandlerTwo::*)()> (TestHandlerTwo*)> >::_M_invoke(std::_Any_data const&) (
    __functor=...) at /usr/include/c++/4.8/functional:2071 
#5 0x000000000040ab5c in std::function<void()>::operator()() const (this=0x641690) 
    at /usr/include/c++/4.8/functional:2471 

Le code:

#include <iostream> 
#include <map> 
#include <memory> 

struct command 
{ 
    std::string cmdname;   // console friendly name 
    std::function<void()> execute; // function to call 
}; 

class IHandler 
{ 
public: 
    virtual void parse(int value) = 0; 
}; 

class BaseHandler : public IHandler 
{ 
public: 
    virtual auto getCommandMap() -> std::map<int, command> const = 0; 

    void parse(int value) override 
    { 
     // this normally takes a stream of bytes and parses it but for this example we hardcode it. 
     auto search = getCommandMap().find(value); 
     if (search == getCommandMap().end()) 
     { 
      return; 
     } 
     std::cout << "Function is " << (search->second.execute ? "callable" : "not callable") << std::endl; 
     if (search->second.execute) 
     { 
      search->second.execute(); 
     } 
     return; 
    } 
}; 

void golden_retriever() 
{ 
    std::cout << "Chases cat" << std::endl; 
} 
class TestHandlerTwo : public BaseHandler 
{ 
    std::map<int, command> commandMap = 
    { 
     { 0x02, { "Handled", golden_retriever } }, 
     { 0x03, { "Test", std::bind(&TestHandlerTwo::labrador, this) } } 
    }; 
public: 
    void labrador() 
    { 
     std::cout << "Chases birds" << std::endl; 
    } 
    virtual auto getCommandMap() -> std::map<int, command> const override 
    { 
     return commandMap; 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    auto testHandler = std::shared_ptr<IHandler>(new TestHandlerTwo()); 
    testHandler->parse(0x02); 
    testHandler->parse(0x03); 
    return 0; 
} 

dont la sortie est la suivante:

(gdb) run 
Starting program: /home/master/test/main 
Function is callable 
Chases cat 
Function is callable 

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000000000 in ??() 

Mon utilisation de bind semble correcte selon ce article et la question déjà posée sur StackOverflow, alors quel est le problème avec mon code?

+1

Comment utilisez-vous alors commandMap? J'ai effectué un test très simple et votre code fonctionne. –

+0

Donnez-nous un programme complet que nous pouvons compiler et exécuter. –

+0

@JohnZwinck Fait. –

Répondre

1

Vous accédez à l'itérateur après la destruction du conteneur (carte).

à BaseHandler :: analyser

void parse(int value) override 
{ 
    // !!here, you constructs a map, and destruct it immediately 
    // which invalidates the iterator 
    // auto search = getCommandMap().find(value); 
    // if (search == getCommandMap().end()) 
    // { 
    //  return; 
    // } 
    // change to these three lines 
    auto&& commandMap = getCommandMap(); 
    auto&& search = commandMap.find(value); 
    if (search == commandMap.end()) return; 

    std::cout << "Function is " << (search->second.execute ? "callable" : "not callable") << std::endl; 
    if (search->second.execute) 
    { 
     search->second.execute(); 
    } 
    return; 
} 

Voir BaseHandler :: getCommandMap

// this always create a copy of original map, which considered 
// temporary, destroys after execution of the statement if not 
// being explicitly held. 
virtual auto getCommandMap() -> std::map<int, command> const = 0; 
+0

Alors, pourquoi cela fonctionne-t-il avec la fonction non-membre, mais échoue avec la fonction membre? Et travailler sur Clang/OSX? Pot-chance? –

+0

Il apparaît à la fin que j'avais seulement besoin de 'command commandMap = getCommandMap();' –