directory iterator
-
so, ich hab eure ratschläge mal versucht zu realisieren und die klasse überarbeitet.
also ich finde sie sieht gleich viel schöner aus und die ersten test haben auch funktioniert
Bitte gebt mir eine kleine rückmeldung, ob ihr das so gemeint habt und ob ich so für den anfang zufrieden sein kann.
boost::iterator_facade
habe ich nicht genommen, weil wenn ich boost benutzen würde wer der sinn des selberschreibens weg und ich könnte gleich boost::filesystem::directory_iterator nehmen

(nurnoch ~100 zeilen)
#include "..\compileconfig.h" #ifndef DELTA_FILE_directory_iterator_H #define DELTA_FILE_directory_iterator_H #include <string> #include <memory> //#include <cstdio> #include <Windows.h> #include "..\core\include.h" #include "path.h" namespace delta{ namespace file{ class directory_iterator{ public: typedef std::input_iterator_tag iterator_category; // input- und single pass iterator typedef file::path value_type; typedef std::ptrdiff_t difference_type; typedef const file::path* pointer; typedef const file::path& reference; // const-iterator static directory_iterator end(){ directory_iterator ret; ret.current.clear(); return ret; } public: // construction directory_iterator() // end-iterator : find_data() , hfile() , current() {} explicit directory_iterator(const file::path& p) : hfile( FindFirstFile( (p.wstring()+L"*").c_str() , &find_data ), &FindClose ) , current( hfile.get() != INVALID_HANDLE_VALUE? find_data.cFileName: TEXT("") ) {} public: // operators directory_iterator& operator ++ (){ forward(); return *this; } directory_iterator operator ++(int) { directory_iterator tmp = *this; forward(); return tmp; } directory_iterator& operator += (int num){ if(num < 0) assert("delta::file::directory_iterator: no backward traversing"); while(num--) forward(); return *this; } directory_iterator operator + (int num) const{ directory_iterator tmp = *this; return tmp += num; } bool operator == (const directory_iterator& other) const{ return (current == other.current); } bool operator != (const directory_iterator& other) const{ return (current != other.current); } #if defined (_MSC_VER) && (_MSC_VER < 1300) #pragma warning(disable:4284) // infix notation problem when using iterator operator -> #endif const file::path & operator * () { return current; } const file::path * operator ->() { return ¤t; } private: // step forward to the next file void forward(){ if(FindNextFile(hfile.get(), &find_data)) current.assign(find_data.cFileName); else current.clear(); } private: typedef std::shared_ptr< std::remove_pointer< HANDLE >::type > shared_handle; WIN32_FIND_DATA find_data; shared_handle hfile; file::path current; // current filepath }; };// ns: file };// ns: delta #endif DELTA_FILE_directory_iterator_H
-
Hallo Jannik,
Zeile 29 sollte überflüssig sein. Ich kenne die Implementierung von file::path zwar nicht, aber der Defaultkonstruktor sollte einen 'gültigen' leeren Pfad erzeugen. Dann wird aber auch die statische Methode end() überflüssig, es sei denn wegen 'syntactic sugar'.
Ist nur formal, aber in Zeile 41 fehlt
find_datain der Initialisierungsliste. Es gibt statisch Test (Lint), die das an-meckern würden.Die Operatoren operator+ und operator+= sind unnötig, da sie mit advance realisiert werden können. Sie implizieren dem Anwender lediglich, dass operator+ mit O(1)-Komplexität implementiert ist, was aber nicht der Fall ist (nicht sein kann). Das lädt nur zu einem Fehlgebrauch ein.
Wegen so was hatte ich vor Jahren mal einen dicken Laufzeitfehler in ein Programm eingebaut - ich brauchte mehrere Test beim Kunden, um die Ursache zu ermitteln.operator*() und operator->() sollten und können const sein.
Wenn zwei Iteratoren gleich sind, wenn der Filename gleich ist, so bedeutet dass, dass auch zwei Iteratoren aus unterschiedlichen Directorys gleich sein können. Den operator!= sollte man als !(*this == other) implementieren, um Redundanzen zu vermeiden.
Gruß
Werner
-
Hallo Jannik,
oh, da war aber einer aufmerksam

'syntactic sugar'
cooler begriff

habe alle fehler bis auf einen ausgebessert

Die Operatoren operator+ und operator+= sind unnötig, da sie mit advance realisiert werden können. Sie implizieren dem Anwender lediglich, dass operator+ mit O(1)-Komplexität implementiert ist, was aber nicht der Fall ist (nicht sein kann). Das lädt nur zu einem Fehlgebrauch ein.
Wegen so was hatte ich vor Jahren mal einen dicken Laufzeitfehler in ein Programm eingebaut - ich brauchte mehrere Test beim Kunden, um die Ursache zu ermitteln.verstehe das problem, aber da ich std::advance noch nie benutzt habe weiß ich nicht, wie ich es benutzen kann

-
Hallo Jannik,
gamer8o4 schrieb:
verstehe das problem, aber da ich std::advance noch nie benutzt habe weiß ich nicht, wie ich es benutzen kann

Dafür hatte ich Dir in meinem Posting den Link angegeben. Da gibt es auch ein Beispiel.
oder so:
int main() { using namespace std; file::path dir( TEXT("C:\\*") ); int anz = distance( directory_iterator( dir ), directory_iterator() ); directory_iterator i( dir ); advance( i, anz/2 ); // inkrementiere den Iterator bis zur Hälfte der Files copy( i, directory_iterator(), ostream_iterator< directory_iterator::value_type, wchar_t >( wcout << "Die zweite Haelfte:\n", L"\n" ) ); return 0; }Gruß & Gute Nacht
Werner
-
Werner Salomon schrieb:
Sowas nennt man eine 'shared resource'. Und da das so oft vorkommt, muss man das nicht selber coden, denn es gibt in C++11 eine Klasse, die das kann. Das ist der std::shared_ptr<>. Dem (Smart-)Pointer kann man mitgeben, was er tun soll, wenn er bzw. die letzte seiner Kopien gelöscht wird. Hier wäre das die Funktion
FindClose.Sowas nennt man Move-Only-Type. Man deaktiviert den Kopierkonstruktor/Zuweisungsoperator und schreibt dafür einen Move-Konstruktor und Move-Zuweisungsoperator. Wer die Ressource aus unerfindlichen Gründen sharen will (in deinem Beispiel würde eine Referenz auch genügen), muss das halt mit
shared_ptr<directory_iterator>explizit hinschreiben.
-
in deinem Beispiel würde eine Referenz auch genügen
ein sehr interessanter einfall!!

ich glaub das schreibe ich mal direkt um, ich mag die idee mit der referenz und es erscheint mir sicherer und schneller also...
-
Hallo gamer8o4,
gamer8o4 schrieb:
in deinem Beispiel würde eine Referenz auch genügen
ein sehr interessanter einfall!!
... und es erscheint mir sicherer und schnellerJa - interessanter, schneller, verführerischer - quasi die dunkle Seite von C++.
Ein
directory_iteratorist zunächst einmal ein Iterator. Und ein Iterator muss - um dem C++ Standard zu genügen - 'CopyConstructible' sein. Steht ganz vorn bei dem Anforderungen an einen Iterator. Ist er das nicht, so kannst Du noch nicht mal einen std::copy damit aufrufen. Probiere es aus - mache den Kopierkonstruktor privat - Dein Compiler wird das gar nicht übersetzen!directory_iterator i = ....; copy( i, directory_iterator::end(), ostream_iterator<...>(...) );Praktisch alle Algorithmen verlangen das, wenn auch in dem einen oder anderen Fall der jeweiligen Implementierung ein moveable ausreichen würde. Und was bitte schön sollte man mit eine
shared_ptr<Iterator>anfangen?Gruß
Werner
-
also nicht mit referenzen machen? JA oder NEIN?
-
NEIN
-
gamer8o4 schrieb:
also nicht mit referenzen machen? JA oder NEIN?
Doppelte Verneinung in schriftlicher Kommunikation ist böse. Denkst du nicht auch, dass das nicht so ist? Ja oder Nein?
-
Oh stimmt ja.
Fail.
Ich meine:
JA
-
also JA, okay ich ändere es
