I think that an implicit iterator invalidity guarantee is fulfilled for moving ctor. That is, for all containers, the following should work: std::array :
template<class Container> struct foo_base { Container c; Container::iterator i; foo_base(foo_base&& rhs, bool is_end) : c( std::move(rhs.c) ) , i( get_init(is_end, rhs.i) ) {} Container::iterator get_init(bool is_end, Container::iterator ri) { using std::end;
Sophisticated initialization using the base class is necessary because destination transfer is not required for movement unless the allocator is distributed for transfer destination. An iterator check is required because the end() iterator may not be valid; this check must be performed before moving the container. If you can guarantee that the allocator is distributed (or else the redirection assignment does not invalidate the iterators for your cases), you can use the simpler version below by replacing swap with the move assignment.
NB The only purpose of the get_init function is to enable ADL. It is possible that foo_base has an end member function that disables ADL. The use-declaration stops the unqualified search to find a possible member function, so ADL is always executed. You can also use std::end(c) and get rid of get_init if you are comfortable playing ADL here.
If it turns out that there is no such implicit guarantee to move ctor, there is still an explicit guarantee for swap . For this you can use:
template<class Container> struct foo { Container c; Container::iterator i; foo(foo&& rhs) { using std::end; // enable ADL bool const is_end = (rhs.i == end(rhs.c)); c.swap( rhs.c ); i = get_init(is_end, rhs.i); } Container::iterator get_init(bool is_end, Container::iterator ri) { using std::end; // enable ADL return is_end ? end(c) : ri; } };
However, the swap has some requirements defined in [container.requirements.general] / 7 + 8:
The behavior of calling the container function swap undefined if only the objects to be exchanged have allocators that compare equal or allocator_traits<allocator_type>::propagate_on_container_swap::value is true [...] Any Compare , Pred or Hash objects belonging to a and b must be replaceable and must be replaced by unqualified non-member swap calls. If allocator_traits<allocator_type>::propagate_on_container_swap::value true , then allocators a and b must also be exchanged using an unqualified non-member swap call. Otherwise, they cannot be exchanged, and the behavior is undefined, if only a.get_allocator() == b.get_allocator() .
those. both containers should (but should not) have equal dispensers.
Moving the OTOH design only requires that no exception be thrown (for containers intended for dispensers); the distributor always moves.