当我致电boost::asio::ip::tcp::resolver::async_resolve
时,我的处理程序会收到一个ip::tcp::resolver::iterator
,它会迭代一个或多个ip::tcp::resolver::entries
。 他们的生命是什么,让他们活着的手柄是什么?
例如,如果我获得第一个entry
并向其发起tcp::async_connect
,那么在async_connect
处理程序中,我可以迭代到下一个entry
并启动另一个async_connect
到下一个条目(当然,只要我将iterator
传递给async_connect
处理程序)?
何时清除resolver::iterator
和resolver::entries
?我是否必须做任何特殊的事情,或者只是让它们超出范围而不被任何回调闭合所持有?
(我知道我可以浏览resolver::entries
处理程序中的所有async_resolve
并将它们存储在智能结构或其他任何内容中,以便我控制它们的生命周期,但如果{{1已经在处理它了,如果我让它完成它的工作,我的代码会更简单。)
答案 0 :(得分:2)
迭代器具有值语义。因此,它们的生命周期始终与周围对象的生命周期或它们的存储持续时间相关(自动堆栈,动态堆栈,有时甚至是静态堆栈)。
我想你想知道迭代器的有效性。
好的,the documentation shows迭代器类别为forward iterator。前向迭代器具有“多通道保证”,允许重复取消引用迭代器的副本,产生相同的结果¹。
所以,我们已经过了一半:保持迭代器仍然可以。但是,当然,与任何其他[forward]迭代器一样,我们必须考虑iterator invalidation。
因此,真正的问题归结为:解析器迭代器何时失效。
resolve
函数实现的用例是连接。对于连接,第一个有效的端点就足够了,因此不需要它实际保留列表。
本着“按需付费”的精神,解决方案将状态保持在超过要求的时间是没有意义的。另一方面,如果不支持Multipass,则迭代器在ForwardIterator类别中是没有意义的。
文档什么也没说。我们只有一个办法:深入了解代码
我们发现表面下方的一些步骤:asio/detail/resolver_service.hpp:73
// Asynchronously resolve a query to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl,
const query_type& query, Handler& handler)
{
// Allocate and construct an operation to wrap the handler.
typedef resolve_op<Protocol, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
boost_asio_handler_alloc_helpers::allocate(
sizeof(op), handler), 0 };
resolve_op
显示迭代器是使用basic_resolver_iterator.hpp::create
这导致我们得到答案:line 251
typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
boost::asio::detail::shared_ptr<values_type> values_;
std::size_t index_;
因此,只要您保留有效迭代器(不是结束迭代器)的副本,就可以继续解除引用它。它甚至会为每个解析器条目保留查询参数(host_name
和service_name
)的副本。这似乎有些浪费,但我认为在设计缓存方案时可以派上用场。
其中翻译“它们始终有效”(如果它们始终有效)。
¹,而不是例如输入迭代器
²通常,C ++实现遵循 零开销原则:你不使用什么,你不支付[C ++的设计和演变,1994]