2016-11-24 101 views
2

我无法理解下面代码的行为。 定义符号BUG时,变量this的第三个输出是错误的。调用boost解析函数时捕获值错误:: async_resolve

我认为在方法resolver::async_resolve中有些东西会破坏代码。我想了解什么:-)

感谢

#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

你的错误是不是由于传递给Connect按值VS通过const引用,这是不确定的行为由于呼叫悬空参照拉姆达。

这是因为您在传递给async_resolve的lambda中通过引用捕获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,其又创建一个lambda 其通过参考捕获Connected,并开始异步操作。

  • handler()然后返回,将“Connected”弹出堆栈,将其破坏。

  • ios.run()防止Test::Start()返回,因为它等待async_resolve返回。

  • async_resolve完成,并调用其lambda,该lambda返回调用Connected(),它已被销毁。

您可以通过通过值捕获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

非常感谢,非常明确的解决这个问题。这是一种棘手的问题(恕我直言)。我必须记住,lambda只是另一个对象栈分配,所以我应该小心地通过引用来传递它......任何人都可以提出任何指导原则来避免这种问题的第一位? –

相关问题