我无法理解下面代码的行为。
定义符号BUG
时,变量this
的第三个印记错误。
我认为方法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();
}
答案 0 :(得分:1)
您的错误不是由于值传递给Connect
而是由const引用传递给它,因为调用了对lambda的悬空引用,它的未定义行为。
这是因为您在传递给Connnected
的lambda中通过引用捕获async_resolve
。
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()
会创建&#34; Connected
&#34;堆栈上的lambda并将其传递给Connect
,然后创建一个lambda ,它通过引用捕获Connected
,并启动异步操作。
handler()
然后返回,弹出&#34; Connected
&#34;离开堆栈,破坏它。
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();
}
);
}