2012-06-27 20 views
10

Estoy haciendo una clase C++ 11 que produce una gran cantidad de datos. Actualmente, los datos provienen de una base de datos y no caben por completo en la memoria. Me gustaría proporcionarle al usuario un iterador que se comporte como iteradores STL regulares, pero sería perezoso. Más precisamente, me gustaría ser capaz de hacer algo así:¿Cómo podría hacer mi propio iterador perezoso?

for (auto& item : big_bunch_of_data) { 
    do_stuff_with(item); 
} 

Con elemento que se recuperan de la base de datos única en cada iteración. Si estoy en lo cierto, esta nueva sintaxis es azúcar para

for (stuff::iterator it = big_bunch_of_data.begin();it != big_bunch_of_data.end();it++) { 
    do_stuff_with(*it); 
} 

¿Quiere decir que al proporcionar begin, end y operator++, que podría tener el comportamiento deseado? Y, ¿qué se supone que deben hacer estos métodos? Quiero decir, ¿puedo hacerlos perezosos sin romper cosas?

+1

_ "Actualmente, los datos provienen de una base de datos y no caben completamente en la memoria" _ por lo que sin conocer su base de datos es difícil dar mejores consejos ... pero recuerde que muchas bases de datos SQL proporcionan sus propios mecanismos iteradores internos en la forma de _cursors_ que puede ser de utilidad para usted aquí. – Rook

+1

Estoy usando sqlite, pero eso podría cambiar en el futuro, y no quiero exponer punteros crudos a los usuarios de mi código, es por eso que estoy tratando de encapsular su bastante bueno (y sí, ya vago) API. – Fabien

Respuesta

11

Casi; el compilador buscará en algunos otros lugares para obtener los iteradores de inicio y final si no puede encontrar los métodos begin o end en la clase contenedora; así es como los bucles basados ​​en rango funcionan en matrices, que no tienen los miembros begin y end. También buscará las funciones gratuitas begin y end por ADL, y eventualmente std::begin y std::end, por lo que hay muchas oportunidades para actualizar la base de rango para soporte de bucle a contenedores existentes. La sección 6.5.4 cubre los detalles.

Para su otra pregunta, los iteradores absolutamente pueden ser perezosos! Un buen ejemplo es std::istream_iterator que tiene para ser flojo ya que lee la entrada desde la consola.

El requisito para usar un iterador en un bucle for es que debe cumplir con la categoría del iterador de entrada, que se describe en la sección 24.2.3; las operaciones requeridas para esa categoría son !=, unario *, y pre y post incremento ++.

Para que el lenguaje sepa que ha creado un iterador de entrada, debe heredar de std::iterator<std::input_iterator_tag, T, void, T *, T &> donde T es el tipo de su iterador (sección 24.4.3).

+3

En realidad, no. Utiliza las funciones miembro '.begin()' directamente. Y si no se encuentran tales miembros, utiliza 'begin' a través de ADL, no necesariamente' std :: begin'. –

+0

@ R.MartinhoFernandes gracias por la aclaración. – ecatmur

+0

Bueno, gracias, eso es exactamente lo que necesitaba. – Fabien

Cuestiones relacionadas