Datei in einen vector <string> einlesen. Doppeltes Kopieren?



  • Hallo,
    ich habe mal ne Frage zu folgendem Code:

    bool read_file ( ifstream& in, vector <string>& lines )
    {
    	while ( in.good() && false == in.eof())
    	{
    		string line;
    		getline ( in, line );
    		lines.push_back (line);
    	}
    
    }
    

    Für jede Zeile wird ein string Objekt erzeugt und dieses in den vector geschoben. Was bewirkt dieses push_back? Eigentlich muss doch intern im Vectorobjekt der String noch einmal neu kopiert werden, oder?
    Also, erst wird in den String line reinkopiert und dann in den Vector?
    Ist das nicht doppelt gemoppelt? Geht das nicht direkt in den Vector rein? 😕



  • Für jede Zeile wird ein string Objekt erzeugt und dieses in den vector geschoben. Was bewirkt dieses push_back? Eigentlich muss doch intern im Vectorobjekt der String noch einmal neu kopiert werden, oder?

    Du hast die Frage selbst beantwortet. Korrekt.

    Ist das nicht doppelt gemoppelt?

    Wenn der vector objekte aufnimmt geht das nicht anders. Die objekte müssen value semantik besitzen.

    Geht das nicht direkt in den Vector rein?

    Nein und das macht auch nichts.

    Simon



  • Du kannst aber einen Schritt sparen:

    bool read_file ( ifstream& in, vector <string>& lines ) 
    { 
        lines.reserve(10000); //genügend speicherplatz reservieren
        std::vector<std::string>::iterator it = lines.begin();
        while ( in.good() && false == in.eof()) 
        { 
            //string line; fällt weg 
            getline ( in, *it ); 
            ++it;
        } 
        return true; //oder was auch immer
    
    }
    


  • *edit

    so gehts natürlich nicht nicht. Musst das dann so machen

    bool read_file ( ifstream& in, vector <string>& lines ) 
    { 
        std::vector<std::string> tmp (10000); //platz reservieren
        size_t t(0);
        while ( in.good() && false == in.eof()) 
        { 
            //string line; fällt weg 
            getline ( in, tmp[t]); 
            ++t;
        }
        tmp.resize(t);
        lines.swap(tmp);
        return true; //oder was auch immer
    
    }
    

    Aber ob das mehr sinn macht, weis ich nicht... 😃



  • Geht das nicht direkt in den Vector rein?

    Nein und das macht auch nichts.

    Könnte man nicht anstelle eines strings als Typ für den vektor einen string pointer verwenden?

    vector<wstring*>


  • Mod

    stax76 schrieb:

    Geht das nicht direkt in den Vector rein?

    Nein und das macht auch nichts.

    Könnte man nicht anstelle eines strings als Typ für den vektor einen string pointer verwenden?

    vector<wstring*>

    Du kannst natürlich Pointer auf Strings speichern und sparst dadurch tatsächlich das Kopieren. Die Stringws müssen aber trotzdem irgendwo im Speicher existieren, das heißt üblicherweise, dass du sie vorher mit new anlegst.



  • Wenn es nur um das potentielle Einsparen der Kopie geht, mache ich oft folgendes:

    bool read_file ( ifstream& in, vector <string>& lines )
    {
        // reserve hier könnte ein paar vectorreallocationen sparen
        while ( in.good() && false == in.eof())
        {
            lines.push_back( string() );
            getline ( in, lines.back() );
        }
        return true; //oder was auch immer
    }
    


  • na sowas, *staun*, wassn das fürne funktion: string() 😕



  • oh! schrieb:

    na sowas, *staun*, wassn das fürne funktion: string() 😕

    Was wohl: Ein string-Konstruktor (Leerer String)


  • Mod

    oh! schrieb:

    na sowas, *staun*, wassn das fürne funktion: string() 😕

    Der Konstruktor von String natürlich. Was LordJaxom da zeigt ist ganz einfach: Anstatt in einen temporären String zu lesen und den zu kopieren, fügt er einen leeren String in den vector ein und liest dann in den leeren String.



  • Geht ja doch ohne die string Zwischenstation 🙂
    So gefällt mir das. 👍



  • LordJaxom schrieb:

    ...

    lines.back()...
    

    Oh Mann !!
    *dreimal-vor-die-stirn-klatsch*

    Da habe ich immer mit "[size()-1]" rumgefummelt und es gibt ein Member dafür! 😮
    Peinlich .... aber man lernt eben nie aus!

    Danke,

    Simon2.



  • Simon2 schrieb:

    LordJaxom schrieb:

    ...

    lines.back()...
    

    Oh Mann !!
    *dreimal-vor-die-stirn-klatsch*

    Da habe ich immer mit "[size()-1]" rumgefummelt und es gibt ein Member dafür! 😮
    Peinlich .... aber man lernt eben nie aus!

    Danke,

    Simon2.

    Ja, ein selten gesehener Gast 😉 ebenso wie front() - wie oft sieht man stattdessen vec[0] 😉



  • Warum nicht mit back_inserter und istream_iterator?



  • Stream-Iteratoren schrieb:

    Warum nicht mit back_inserter und istream_iterator?

    Hat sich erledigt, habe übersehen, dass ganze Zeilen gelesen werden sollen.

    Würde aber dennoch folgende Methode bevorzugen:

    bool read_file(std::ifstream &in, std::vector<std::string> &lines)
    {
       do {
           lines.push_back(std::string());
       } while(getline(in, lines.back()));
    
       return !!in; // gerade kein compiler zur hand ob auch return in; geht
    }
    


  • move ftw! 😃

    std::string tmp;
        while (getline(in, tmp))
            lines.push_back(std::move(tmp));
    


  • @Stream-Iteratoren:
    1x pop_back() vergessen, sonst hast du eine leere zeile zuviel am ende von "lines" (pop_back, was für ein Name für eine Funktion 😃 )

    und... wenn die schleife abbricht, wird der returnwert auch immer false sein so wie du das machst. nicht?



  • hustbaer schrieb:

    @Stream-Iteratoren:
    1x pop_back() vergessen, sonst hast du eine leere zeile zuviel am ende von "lines" (pop_back, was für ein Name für eine Funktion 😃 )

    und... wenn die schleife abbricht, wird der returnwert auch immer false sein so wie du das machst. nicht?

    Ja, alte angewohnheit von mir, wenn nicht so etwas wie is im Namen Stimmt du hast recht, aber war auch schon spät 😉
    auftaucht, dass ist 0 der Rückgabewert für Erfolg.



  • Stream-Iteratoren schrieb:

    hustbaer schrieb:

    @Stream-Iteratoren:
    1x pop_back() vergessen, sonst hast du eine leere zeile zuviel am ende von "lines" (pop_back, was für ein Name für eine Funktion 😃 )

    und... wenn die schleife abbricht, wird der returnwert auch immer false sein so wie du das machst. nicht?

    Ja, alte angewohnheit von mir, wenn nicht so etwas wie is im Namen Stimmt du hast recht, aber war auch schon spät 😉
    auftaucht, dass ist 0 der Rückgabewert für Erfolg.

    Oh da ist aber einiges durcheinander geraten, hier die richtig formatierte Version:

    Stimmt du hast recht, aber war auch schon spät 😉
    Ja, alte angewohnheit von mir, wenn nicht so etwas wie is im Namen auftaucht, dass ist 0 der Rückgabewert für Erfolg.



  • @Stream-Iteratoren:
    Ich meinte dass die Funktion *immer* false zurückgibt, und der Rückgabewert dadurch total sinnlos ist.


Anmelden zum Antworten