Iterator / Referenz... Verwirrt??



  • EDIT: Der Code muss nicht zwangsweise korrekt sein, was seinen Zweck angeht. Ich habe ihn noch nicht getestet.

    Hier eine Funktion zum Auflisten von Ordnern in einem Ordner.

    void FilesAndDirs::ListDirectoriesInDirectory(const std::string& Directory, std::vector <std::string>& Directories, bool WithDirectory) {
        WIN32_FIND_DATA found;
        memset(&found, 0, sizeof(found));
        RAII_Handle<HANDLE, WINBASEAPI BOOL WINAPI (*)(HANDLE)> fHandle (FindFirstFile((Directory + "\\*").c_str(), &found), &FindClose);
    
        if (fHandle.get() == INVALID_HANDLE_VALUE)
            return;
    
        while (FindNextFile(fHandle.get(), &found)) {
            if (std::string(found.cFileName) == "..")
                continue;
            if ((found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                if (WithDirectory)
                    Directories.push_back(Directory + "\\" + std::string(found.cFileName)); // Hier wurf von eigenartigem Fehler
                else
                    Directories.push_back(std::string(found.cFileName));
            }
        }
        //FindClose(fHandle.get()); automatisch
    }
    

    Und hier um alle Unterordner aufzulisten und jetzt kommt der Knackpunkt:

    Directories.push_back(Directory);
        std::vector<std::string>::iterator iter = Directories.begin();
        do {
    // nächste Zeile stand zuvor statt "std::string(*iter)" nur *iter
            ListDirectoriesInDirectory(std::string(*iter), Directories, true);
            ++iter;
        } while (iter != Directories.end());
    

    Ich habe mit dem Debugger herausgefunden, dass in der markierten Zeile in der oberen Funktion der Fehler geworfen wird, aber dass dieser bei "Directory" lag, hat mich fast vom umgehauen.
    Nachdem ich eine Element zu dem vector hinzugefügt hatte (der erste Ordnerfund) scheint sich auch die Referenz "Directory" verändert zu haben und mir wurde der Zugriff auf ungültigem Speicherbereich angezeigt.

    Danach habe ich die Änderung (mit Kommentar markiert in zweitem Code) gemacht und alles lief wieder.

    Darf sowas sein? Kann sowas sein?


  • Mod

    Tim06TR schrieb:

    Darf sowas sein? Kann sowas sein?

    Na klar, du hast schließlich eine Referenz auf ein Objekt, welches zwischenzeitlich zerstört wird. Undefiniertes Verhalten eben. Durch deine Änderung erzeugst du künstlich eine temporäre Kopie des referenzierten Objektes, dann geht's wieder.

    Die eigentliche Fehlerursache ist aber, dass du hier Directories praktisch wie eine globale Variable benutzt*. Dadurch bekommst du undurchschaubare Abhängigkeiten, plötzliche unnachvollziehbare Änderungen und schwer zu findende Fehler. Das ist der Grund, warum uns die Altvorderen vor den globalen Variablen gewarnt haben.

    *: Ja, ich sehe, dass es wohl technisch ein Member von FilesAndDirs ist. Aber es wird benutzt wie eine globale Variable. Mach das FilesAndDirs:: vor dem Funktionsnamen weg und man könnte es nicht von einem globalen Programmzustand unterscheiden.



  • Das wird noch skuriler...

    void FilesAndDirs::EnumDirectories(const std::string& Directory, std::vector <std::string>& Directories)
    {
        Directories.push_back(Directory);
        std::vector<std::string>::iterator iter = Directories.begin();
        do {
            ListDirectoriesInDirectory(std::string(*iter), Directories, true);
            for (int i = 0; i < Directories.size(); ++i) {
                std::cout << "_" << Directories[i];   // richtige Ausgabe
                std::cin.get();
            }
            ++iter;
            std::cout << Directories.size() << std::endl;    // Ausgabe 3 (richtig)
            std::cout << "->|" << *iter << "|" << std::endl; // leerer String???
        } while (iter != Directories.end()); // Bedingung ist false
    }
    

    Was ist denn hier mit dem Iterator kaputt?

    EDIT: Ohne Verwendung von Iteratoren, Also:

    void FilesAndDirs::EnumDirectories(const std::string& Directory, std::vector <std::string>& Directories)
    {
        Directories.push_back(Directory);
        unsigned int i = 0;
        do {
            ListDirectoriesInDirectory(std::string(Directories[i]), Directories, true);
            ++i;
        } while (i != Directories.size());
    }
    

    läuft alles planmäßig.


  • Mod

    Sofern du den Fehler nicht verbessert hast, ist immer noch das gleiche kaputt. Durch das push_back in ListDirectoriesInDirectory werden alle Iteratoren ungültig.



  • SeppJ schrieb:

    Sofern du den Fehler nicht verbessert hast, ist immer noch das gleiche kaputt. Durch das push_back in ListDirectoriesInDirectory werden alle Iteratoren ungültig.

    Danke, der Wortlauft war wichtig. Jetzt habe ich es verstanden!

    EDIT: Irgendwie ungünstig... -.-


Anmelden zum Antworten