2016-05-11 3 views
2

У меня есть класс, который вызывает функцию в зависимости от переданного значения. Функция недействительна без параметров и сохраняется на карте (наряду с некоторой другой информацией).Ошибка сегментации при вызове функции связанного члена

Программа компилируется и функция golden_retriever работает, как ожидалось, но когда labrador называется программа SIGSEVs со следующей информацией в БГД (за # 5 это из тестового класса и в реальный код):

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 

код:

#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; 
} 

выход из которых является:

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

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

Мое использование bind кажется правильным в соответствии с этим article и вопрос уже задан на StackOverflow, так что же не так с моим кодом?

+1

Как вы затем использовать commandMap? Я провел очень простой тест, и ваш код работает. –

+0

Дайте нам полную программу, которую мы можем скомпилировать и запустить. –

+0

@JohnZwinck Done. –

ответ

1

Вы получаете доступ к итератору после уничтожения контейнера (карты).

В BaseHandler :: синтаксический

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; 
} 

См 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

Итак, почему он работает с функцией, отличной от членов, но не работает с функцией-членом? И работайте над Clang/OSX? Пот-удачи? –

+0

В конце концов мне нужно было только 'auto commandMap = getCommandMap();' –