2012-06-27 2 views
10

Ich mache eine C++ 11-Klasse, die eine große Menge an Daten produziert. Diese Daten stammen derzeit aus einer Datenbank und können nicht vollständig in den Speicher passen. Ich möchte dem Benutzer einen Iterator zur Verfügung stellen, der sich wie normale STL-Iteratoren verhält, aber das wäre faul. Genauer gesagt könnte ich Folgendes tun:Wie könnte ich meinen eigenen faulen Iterator erstellen?

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

Mit Element wird nur bei jeder Iteration aus der Datenbank abgerufen. Wenn ich Recht habe, diese neue Syntax ist Zucker für

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

Bedeutet es, dass begin durch die Bereitstellung, end und operator++ ich das gewünschte Verhalten haben könnte? Und was sollen diese Methoden tun? Ich meine, kann ich sie faul machen, ohne etwas kaputt zu machen?

+1

_ "Diese Daten kommen derzeit aus einer Datenbank und können nicht vollständig in den Speicher passen" _ also, ohne Ihre Datenbank zu kennen, ist es schwierig, bessere Ratschläge zu geben ... aber bedenken Sie, dass viele SQL-Datenbanken ihre eigenen internen Iterator-Mechanismen enthalten die Form von _cursors_, die Ihnen hier nützlich sein könnte. – Rook

+1

Ich benutze sqlite, aber das könnte sich in der Zukunft ändern, und ich möchte keine rohen Zeiger den Benutzern meines Codes zugänglich machen, deshalb versuche ich, seine ziemlich gute (und ja, schon faul) einzukapseln API. – Fabien

Antwort

11

Fast; Der Compiler sucht an einigen anderen Stellen nach den Start- und Ende-Iteratoren, wenn er die Methoden begin oder end für die Containerklasse nicht finden kann. So arbeiten bereichsabhängige for-Schleifen auf Arrays, die keine begin und end Member haben. Es wird auch nach freien Funktionen begin und end von ADL, und schließlich std::begin und std::end suchen, so gibt es viele Möglichkeiten, um Range-basierte for-Loop-Unterstützung für bestehende Container nachrüsten. Abschnitt 6.5.4 behandelt die Details.

Für Ihre andere Frage können Iteratoren absolut faul sein! Ein gutes Beispiel ist std::istream_iterator, die hat zu faul sein, wie es Eingabe von der Konsole liest.

Die Anforderung, einen Iterator in einer for Schleife zu verwenden ist, dass es die InputIterator Kategorie erfüllen sollte, die in Abschnitt 24.2.3 beschrieben ist; Die erforderlichen Operationen für diese Kategorie sind !=, unary * und Pre- und Post-Inkrement ++.

Um der Sprache mitzuteilen, dass Sie einen Eingabe-Iterator erstellt haben, sollten Sie von std::iterator<std::input_iterator_tag, T, void, T *, T &> erben, wobei T der Typ ist, mit dem Ihr Iterator handelt (Abschnitt 24.4.3).

+3

Eigentlich nein. Es verwendet '.begin()' Elementfunktionen direkt. Und wenn keine solchen Mitglieder gefunden werden, verwendet es "begin" bis ADL, nicht unbedingt "std :: begin". –

+0

@ R.MartinhoFernandes danke für die Klarstellung. – ecatmur

+0

Nun, danke, genau das habe ich gebraucht. – Fabien