verificar usar qué pueden para métodos hay elementos cplusplus contenedor clase c++ stl iterator

c++ - cplusplus - qué métodos de la clase std:: deque se pueden usar para verificar si hay elementos en el contenedor



¿Probando si un iterador apunta al último elemento? (9)

¿Por qué necesita realizar un comportamiento especial solo si el elemento es el último?

¿Qué pasa con esto? El plan es simplemente comparar la dirección del elemento del iterador con la dirección del último elemento en el contenedor, con una verificación para asegurarse de que el elemento no esté en el final (haciendo que la llamada de back segura):

if (itr != Mine.end() && &*itr == &Mine.back()) { doSomething; }

Tengo un iterador stl resultante de un std :: find () y deseo probar si es el último elemento. Una forma de escribir esto es la siguiente:

mine *match = someValue; vector<mine *> Mine(someContent); vector<mine *>::iterator itr = std::find(Mine.begin(), Mine.end(), match); if (itr == --Mine.end()) { doSomething; }

Pero me parece que disminuir el iterador end () está buscando problemas, por ejemplo, si el vector no tiene elementos, entonces sería indefinido. Incluso si sé que nunca estará vacío, todavía parece feo. Estoy pensando que tal vez rbegin () es el camino a seguir, pero no estoy seguro de cuál es la mejor manera de comparar el iterador directo con un iterador inverso.


Aquí hay otra solución potencial:

template<class Iterator, class Container> bool is_last(Iterator it, const Container& cont) { // REQUIREMENTS: // the iterator must be a valid iterator for `cont` if( it == cont.end() ) return false; // or throw if you prefer return (++it) == cont.end(); }


Este es esencialmente el mismo problema que eliminar un nodo de una lista de enlaces individuales. Debe tener dos iteradores, uno que sigue a un nodo detrás del otro, de modo que cuando el iterador "adelante" llegue al nodo que desea eliminar (o cualquier operación; en su caso, el nodo deseado sería el final), el " el siguiente "iterador está apuntando al nodo antes (en su caso, este sería el nodo final).


Hacer esto:

// defined in boost/utility.hpp, by the way template <typename Iter> Iter next(Iter iter) { return ++iter; } // first check we aren''t going to kill ourselves // then check if the iterator after itr is the end if ((itr != Mine.end()) && (next(itr) == Mine.end())) { // points at the last element }

Eso es todo. Nunca te da un comportamiento indefinido, funciona en todos los iteradores, buen día.

Envuélvelo por diversión

template <typename Iter, typename Cont> bool is_last(Iter iter, const Cont& cont) { return (iter != cont.end()) && (next(iter) == cont.end()) }

Dando:

if (is_last(itr, Mine))

Si eres alérgico a las funciones de utilidad / código de aspecto agradable, haz:

if ((itr != Mine.end()) && (itr + 1 == Mine.end()))

Pero no puedes hacerlo en iteradores de acceso no aleatorio. Éste funciona con iteradores bidireccionales:

if ((itr != Mine.end()) && (itr == --Mine.end()))

Y es seguro desde el end() > itr por la primera comprobación.


Primero necesitaría una forma de determinar si un iterador es inverso , que se mostró ingeniosamente aquí :

#include <iterator> #include <type_traits> template<typename Iter> struct is_reverse_iterator : std::false_type { }; template<typename Iter> struct is_reverse_iterator<std::reverse_iterator<Iter>> : std::integral_constant<bool, !is_reverse_iterator<Iter>::value> { };

Entonces podrías tener dos sabores para realizar la prueba.

template<bool isRev> // for normal iterators struct is_last_it { template<typename It, typename Cont> static bool apply(It it, Cont const &cont) { // you need to test with .end() return it != cont.end() && ++it == cont.end(); } }; template<> // for reverse iterators struct is_last_it<true> { template<typename It, typename Cont> static bool apply(It it, Cont const &cont) { // you need to test with .rend() return it != cont.rend() && ++it == cont.rend(); } };

Y una sola función de interfaz.

template<typename It, typename Cont> bool is_last_iterator(It it, Cont const &cont) { return is_last_it<is_reverse_iterator<It>::value>::apply(it, cont); };

Luego, para cada tipo de iterador (inverso / recto) puede usar la función de interfaz

int main() { std::vector<int> v; v.push_back(1); auto it (v.begin()), ite(v.end()); // normal iterators auto rit(v.rbegin()), rite(v.rend()); // reverse iterators std::cout << is_last_iterator(it, v) << std::endl; std::cout << is_last_iterator(ite, v) << std::endl; std::cout << is_last_iterator(rit, v) << std::endl; std::cout << is_last_iterator(rite, v) << std::endl; return 0; }

Tenga en cuenta que algunas implementaciones (aparte de std::begin() y std::end() que son bastante comunes, también incluyen std::rbegin() y std::rend() . Cuando sea posible, use este conjunto de funciones en lugar de miembro .begin() etc.


Sí, no es seguro disminuir (o incrementar) el end si el vector puede estar vacío. Incluso es un poco inseguro hacer lo mismo con un puntero, aunque es probable que te salgas con la tuya.

Para estar realmente seguro, use la resta y los valores conocidos como seguros y válidos:

if ( Mine.end() - itr == 1 )

Para compatibilidad con todos los iteradores hacia adelante (como en slist , a diferencia de los iteradores de acceso aleatorio de vector y deque ), use

if ( std::distance( itr, Mine.end() ) == 1 )

o si está preocupado por el rendimiento pero tiene iteradores bidireccionales (incluido cualquier contenedor C ++ 03)

if ( itr != Mine.end() && itr == -- Mine.end() )

o el caso verdaderamente anal de solo iteradores hacia adelante y O (1) tiempo,

if ( itr != Mine.end() && ++ container::iterator( itr ) == Mine.end() )

o si está muy decidido a evitar nombrar a la clase iterador,

if ( itr != Mine.end() && ++ ( Mine.begin() = itr ) == Mine.end() )


Si lo haces:

if(itr != Mine.end() && itr == --Mine.end())

Debería estar bien. Porque si itr no está al final, debe haber al menos 1 elemento en el contenedor y, por lo tanto, end debe dar un resultado de valor cuando se reduzca.

Pero si todavía no te gusta eso, hay muchas maneras de hacer algo equivalente, como muestran todas las otras respuestas.

Aquí hay otra alternativa:

if(itr != Mine.end() && std::distance(Mine.begin(), itr) == Mine.size()-1)


Tratando de hacer esta respuesta lo más simple y versátil posible:

if( itr!=Mine.end() && itr== --Mine.end())

Si el iterador no es bidireccional,

if( itr!=Min.end() && ++decltype(itr)(itr)==Mine.end())

El segundo crea una copia temporal de itr y la incrementa para probar contra el iterador final.

En ambos casos, la primera prueba evita los contenedores vacíos para desencadenar una situación indefinida.


Una mejor manera sería copiar el iterador y luego incrementarlo. A continuación, puede probar la versión incrementada contra end() . Si tiene cuidado, puede usar un incremento posterior para evitar la necesidad de copiarlo formalmente.

if (++vector<mine*>::iterator(itr) == Mine.end())

Si itr ya podría estar al final:

if (itr == Mine.end() || ++vector<mine*>::iterator(itr) == Mine.end())

O, basado en la respuesta de GMan pero un poco más seguro:

if (Mine.Length() == 0 || itr == Mine.End() || &*itr == &Mine.back())

Acabo de arreglar el último de nuevo, ya que estaba equivocado acerca de &* .