2016-11-24 3 views
2

以下のコードの動作を理解できません。 シンボルBUGを定義するとき、変数thisの3番目の印刷が間違っています。boost resolve :: async_resolveを呼び出すときにキャプチャされた値の値が正しくない

私はコードに壊れている方法resolver::async_resolveに何かがあると思います。私はあなたのバグがconst参照によって対値でConnectに渡しによるものではないおかげ

#include <boost/asio.hpp> 
#include <iostream> 

using namespace std; 

template <typename F> 
#ifdef BUG 
void Connect(boost::asio::ip::tcp::resolver& resolver, F Connected) 
#else 
void Connect(boost::asio::ip::tcp::resolver& resolver, const F& Connected) 
#endif 
{ 
    resolver.async_resolve(
     boost::asio::ip::tcp::resolver::query{ "localhost", "8088" }, 
     [&Connected](const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator i) 
     { 
      Connected(); 
     } 
    ); 
} 

struct Test 
{ 
    void Start() 
    { 
     cout << "this1 " << hex << this << dec << endl; 
     auto handler = [this]() 
     { 
      cout << "this2 " << hex << this << dec << endl; 
      boost::asio::ip::tcp::resolver resolver{ ios }; 
      Connect(resolver, [this]() 
       { 
        cout << "this3 " << hex << this << dec << std::endl; 
       } 
      ); 
     }; 
     handler(); 
     ios.run(); 
    } 

    boost::asio::io_service ios; 
}; 

int main() 
{ 
    Test t; 
    t.Start(); 
} 

答えて

1

:-)、それが原因ラムダへのダングリング参照を呼び出すには、未定義の動作だかを理解したいと思います。

これは、async_resolveに渡されたラムダで参照によってConnnectedをキャプチャしているためです。

resolver.async_resolve(
    boost::asio::ip::tcp::resolver::query{ "localhost", "8088" }, 
    [&Connected](const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator i) 
    { 
     Connected(); // Connected is captured by reference 
    } 
); 

Connected()が呼び出されるまでに、スタックからポップされて破棄されました。

void Start() 
{ 
    cout << "this1 " << hex << this << dec << endl; 
    auto handler = [this]() 
    { 
     cout << "this2 " << hex << this << dec << endl; 
     boost::asio::ip::tcp::resolver resolver{ ios }; 
     Connect(resolver, [this]() 
      { 
       cout << "this3 " << hex << this << dec << std::endl; 
      } 
     ); 
    }; 
    handler(); // after this function returns Connected will be destructed 
    ios.run(); // the thread is blocked in ios.run until the resolve returns 
} 
  • handler()へのコールスタックの「Connected」ラムダを作成しConnectに渡し、順番に参照によってConnectedを捕捉ラムダを生成し、非同期動作を開始します。

  • は、スタックから "Connected"をポップして破棄し、破棄します。

  • ios.run()async_resolveが戻るのを待ってからTest::Start()が返されないようにします。

  • async_resolveが完了し、そのラムダを呼び出します。返されるのは、破棄されたConnected()です。

あなたはは、値による

void Connect(boost::asio::ip::tcp::resolver& resolver, F Connected) 
{ 
    resolver.async_resolve(
     boost::asio::ip::tcp::resolver::query{ "localhost", "8088" }, 
     [Connected](const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator i) 
     { 
      Connected(); 
     } 
    ); 
} 
+0

どうもありがとう、非常に明確にConnectedをキャプチャすることによりこの問題を解決することができます。それは、(IMHO)にスポットするバグトリッキーの一種です。私はラムダが割り当てられた別のオブジェクトスタックであることを覚えておく必要があるので、参考にして渡すのが慎重でなければなりません...誰でもこの種の問題を避けるためのガイドラインを提案できますか? –

関連する問題