Deconstructing The Question
Iterators have value semantics. So their lifetime is always bound to the lifetime of the surrounding object, or their storage duration (stack for automatic, heap for dynamic and sometimes even others for e.g. static).
I think you want to know about the validity of the iterators instead.
Well, the documentation shows that the iterator category is forward iterator. Forward iterators have the "Multipass guarantee", allowing repeated dereference of copies of iterators, yielding the same result¹.
So, we're halfway: it could still be ok to keep the iterators. However, of course, like with any other [forward] iterator, we have to think of iterator invalidation.
So, the real question boils down to: when are resolver iterators invalidated.
What Do We Know?
The usecase the resolve
function fulfills is connection. For connection, the first endpoint that works is enough, so there is no need for it to actually retain a list.
In the spirit of pay-for-what-you-need² it would not make sense for resolver to keep the state around longer than required. On the other hand it would not make sense for the iterator to be in the ForwardIterator category if Multipass weren't supported.
The docs say nothing. We have only one recourse: dive into the code
Dive Into The Code
Some steps below the surface we find: 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
shows that the iterator is created using basic_resolver_iterator.hpp::create
And this leads us to the answer: in line 251
typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
boost::asio::detail::shared_ptr<values_type> values_;
std::size_t index_;
So, as long as you a keep a copy of a valid the iterator (not the end iterator) you can keep dereferencing it. It will even keep a copy of the query parameters (host_name
and service_name
) with each resolver entry. This seems slightly wasteful but I suppose could come in handy when devising a caching scheme.
SUMMARIZING:
- Q. When are resolver iterators invalidated?
- A. When the last copy of a valid iterator is destructed.
Which translates "they always remain valid" (if they were ever valid).
¹ as opposed to e.g. input iterators
² In general, C++ implementations obey the
zero-overhead principle: What you don’t use, you don’t pay for [The Design and Evolution of C++, 1994]