我无法理解下面代码的行为。定义符号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();
}发布于 2016-11-24 21:32:52
您的错误不是通过值传递给Connect而不是通过const引用传递,而是由于调用对lambda的悬空引用而导致的未定义行为。
这是因为在传递给async_resolve的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()的调用在堆栈上创建"Connected“lambda并将其传递给Connect,后者将创建一个lambda ,该通过引用捕获,并启动一个异步操作。handler()返回,从堆栈中弹出"Connected“,销毁它。ios.run()在等待async_resolve返回时阻止Test::Start()返回。async_resolve完成了,并调用了它的lambda,作为回报,它调用了已被销毁的Connected()。您可以通过捕获 by value来解决这一问题。
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();
}
);
}https://stackoverflow.com/questions/40791668
复制相似问题