ofstream Pfadangabe
-
Mit C++11 würde der Code funktionieren. Umsteigen lohnt sich
Nur ärgerlich, wenn man sich auf ein Feature freut und merkt, dass der eigene Compiler es doch noch gar nicht unterstützt.
Aber ofstream sollte überall schon string unterstützen, da hast du recht.
-
Der Tobi schrieb:
Weil ofstream bzw. die open() Methode noch mit C-Strings arbeitet.
void write(string filename) { ofstream writeData; writeData.open(filename.c_str());Sollte anhand des Errors auch zu erkennen sein.
Ahh..ok! Das wusste ich nicht. Wenn ich also einen String direkt als Parameter schreibe, dann wird er als C-String interpretiert?
manni66 schrieb:
Mit C++11 würde der Code funktionieren. Umsteigen lohnt sich

Mmmh...blöde Frage vielleicht, aber wie kriege ich meinen g++ denn, C++11 Code zu kompilieren?
LG, freakC++
-
compileraufruf: g++ -std=c++0x ...
aber eigentlich sollte dir der g++ ne fehlermeldung geben und dir sagen, was du in dem fall falsch gemacht hast bzw. was du machen musst.
http://ideone.com/qSSHJj hier hast du mal nen beispiel.
-
ok. Vielen Dank!
Ich habe noch eine andere Frage. Ich habe eine kleine Funktion geschrieben, die mir eine Textdatei in einem vector speichern soll:
template <typename T> void read(T& t, string filename) { ifstream readData; readData.open(filename.c_str()); string line; while (!readData.eof()) { getline(readData,line); t.push_back(line); } readData.close(); }Für einen vector<string> funktioniert diese Methode einwandfrei!
Nun weiß ich aber, dass ich manchmal auch Dateien habe, in denen nur Zahlen stehen. Dann ist sichergestellt, dass ich einen vector<float> als ersten Parameter bekomme. Dann jedoch funktioniert meine Methode verständlicherweise nicht mehr.
Zwar weiß ich, wie ich einen String in einen float umwandle (z.B. mit alof), aber ich kann momentan nicht das Problem der Fallunterscheidung lösen:
Ich müsste also irgendwie meiner Prozedur beibringen: Falls Du einen vector<float> bekommst, dann musst Du die eingelesenen Zahlen in float umwandeln.
Kann mir da jemand weiterhelfen?
Vielen Dank
lg, freakC++
-
Da musst du dich entscheiden, was du überhaupt willst. Zeilenweises Lesen ist generell anders als formatiertes Lesen von Datentypen. Verallgemeinert sähe deine Funktion so aus (ungetestet):
// Anstatt einem Container ist es üblicher, einen Iterator zu übergeben. Durch die // Nutzung von push_back schränkst du den Container nämlich schon praktisch auf // einige wenige ein. Dabei könnte die Funktion eigentlich mit allen containerartigen // Objekten funktionieren. // Stringkopien sind auch zu vermeiden. Referenzen nutzen. template <typename OutputIterator> void read(OutputIterator out, string const &filename) { ifstream file(filename.c_str()); // Besser wäre, gleich einen allgemeinen // istream zu benutzen, anstatt einen // Dateinamen zu übergeben. // Dein ofstream hatte einen doofen Namen // Deine Leseschleife war falsch und liest die letzte Zeile doppelt. while (file >> out++); }Dies nutzt den Operator >>, welches die übliche Art und Weise ist, Datentypen "lesbar" zu machen. Bei Strings bedeutet dies natürlich wortweises anstatt zeilenweises Lesen. Du könntest noch eine Fallunterscheidung (durch Templatespezialisierung, ist vermutlich noch zu kompliziert für dich) für diesen Fall einbauen, die dann getline nutzt.
Du bist übrigens (Kommentar zu Zeile 14) der üblichen Seuche verfallen (schlechtes Buch?): Wenn du prüfst, liest, verarbeitest, dann wirst du im Falle eines Fehler einmal verarbeiten, obwohl ein Fehler aufgetreten ist, da die Prüfung erst danach erfolgt. Das tollpatschige open, close und eof deuten auch auf ein schlechtes Buch hin, denn man hätte eine um Längen bessere Lösung, wenn man einfach gar nichts schreiben würde! (siehe wie ich das mache)
-
Hallo SeppJ!
Danke für deinen ausführlichen Post. Deine Anmerkungen verstehe ich soweit. Wahrscheinlich liegt mein schlecher Stil an zu wenig Erfahrung :).
Bezüglich des Iterators im Parameter. Bei mir konkret ist festgelegt, dass ich einen Container übergeben muss. Ich bekomme entweder einen vector oder eine list. Auch wenn deine Lösung schöner ist, muss ich mich hier an die Regel, die mir vorgegeben ist, halten.
Da lag genau mein Problem. Wie krieg ich diese Art "Fallunterscheidung" mit Containern hin, also konkret mit vector und list?
Vielen Dank
LG, freakC++
-
Du machst es dann eben wieder so wie du es vorher hattest, anstatt der allgemeinen Lösung. vector und list haben ebenfalls einen Membertyp value_type, der auch das gleiche bedeutet wie bei Iteratoren. Also:
template <typename ContainerType> void read(ContainerType &container, string const &filename) { ifstream file(filename.c_str()); typedef typename ContainerType::value_type ElementType; // Könnte man sich auch sparen, // da nur einmal benutzt. // Finde ich aber übersichtlicher so. for (ElementType value; file >> value; container.push_back(value)); }Mir ist übrigens noch aufgefallen, dass meine Leseschleife oben ziemlich umständlich war. Ich hab's editiert. Sieh mal, wie einfach eine solch allgemeine Funktion aussehen kann. Wenn du dir jetzt noch denkst, dass der Stream direkt übergeben wird, anstatt als Dateiname, dann ist es nur noch ein Einzeiler. Und das ist auch der Grund, wieso solche allgemeinen "Lesefunktionen" unüblich sind. Man gewinnt dadurch nichts. Im Gegenteil wird man, besonders bei deiner Vorgabe, unnötig eingeschränkt.
-
Hallo SeppJ!
Ahh...der Clue ist wohl Container::value_type! Das kannte ich nicht und damit wird dann wohl automatisch der Typ des übergebenen Containers ausgelesen.
Eine Frage habe ich bezüglich dieser Stelle im Code:
file >> value
Zwar hast Du bereits dazu etwas geschrieben, aber es mir noch nicht so ganz klar. Ich stelle mir vor, dass in "value" jetzt der Typ meines Containers steht, also zum Beispiel float. Was shifte ich hier in einen Typ (ich weiß, dass dieser Satz schrecklich ist, aber ich kann mir die Zeile noch nicht erklären)?
Vielen Dank
LG, freakC++
-
Shiften?
Du musst doch schon einmal gesehen haben, dass man operator>> im Zusammenhang mit Streams zum Lesen benutzt? C++-Buch, um Seite 2 herum? Und wieso sollte value ein Typ sein? Das ist eine ganz normale Variable!Angenommen, es sollte kein Template erstellt werden, dann sähe der Code für vector<int> so aus:
void read(vector<int> &container, string const &filename) { ifstream file(filename.c_str()); for (int value; file >> value; container.push_back(value)); }Verstehst du es nun?
-
keeine Panik, SeppJ! Natürlich weiß ich das. Ich dadurch nur betonben, dass mir gerade die interne Funktionsweise des Schleifenkopfs nicht ganzg klar ist. Daher habe ich ja auch in Klammern geschrieben, dass mir bewusst ist, wie schrecklich diese Aussage ist

Vielen Dank für die Erklärung und viele Grüße
freakC++
-
Ach so. Die Schleife als while ist vielleicht einfacher lesbar:
int value; while (file >> value) { container.push_back(value) }Ich mag die for-Schreibweise, da man alles schön kompakt hat und value auch lokal ist.