调用 boost 时捕获值的错误值 resolve::async_resolve
Wrong value for captured value when calling boost resolve::async_resolve
我无法理解下面代码的行为。
定义符号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();
}
您的错误不是由于通过值而不是通过 const 引用传递给 Connect
,而是由于调用对 lambda 的悬空引用而导致的未定义行为。
这是因为您在传递给 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
”lambda 并将其传递给 Connect
,后者又创建了一个 lambda 通过引用捕获Connected
,并开始异步操作。
handler()
然后 returns,从堆栈弹出“Connected
”,销毁它。
ios.run()
在等待 async_resolve
到 return.
[ 时阻止 Test::Start()
returning =53=]
async_resolve
完成,并调用其 lambda,后者在 return 中调用 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();
}
);
}
我无法理解下面代码的行为。
定义符号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();
}
您的错误不是由于通过值而不是通过 const 引用传递给 Connect
,而是由于调用对 lambda 的悬空引用而导致的未定义行为。
这是因为您在传递给 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
”lambda 并将其传递给Connect
,后者又创建了一个 lambda 通过引用捕获Connected
,并开始异步操作。handler()
然后 returns,从堆栈弹出“Connected
”,销毁它。
[ 时阻止ios.run()
在等待async_resolve
到 return.Test::Start()
returning =53=]async_resolve
完成,并调用其 lambda,后者在 return 中调用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();
}
);
}