2016-05-11 24 views
2

渡された値に応じて関数を呼び出すクラスがあります。この関数はパラメータなしでvoidであり、マップに(その他の情報と共に)格納されています。バインドされたメンバー関数を呼び出すときのセグメンテーションフォールト

プログラムをコンパイルして機能予想通りgolden_retriever作品が、labradorは(#5を超え、それはテストクラスのうち、実際のコードの中にある)GDBに次の情報をプログラムSIGSEVs呼ばれる:

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完了。 –

答えて

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();'のみです。 –

関連する問題