for_each ausgabe einer klasse
-
Ist das gleiche. Was dir lieber ist.
Grüssli
-
Also langsam vergeht mir der Spaß...
Jetzt bringt der Compiler von Visual Studio auch einen Überlauf Fehler...
Hier der Code:
//main.cpp------------------------------------------------------------------------- #include <string> #include <iostream> #include <list> #include "adressliste.h" const char dateiname[]="datei.txt"; int main() { Adressliste Freunde; //--einfuegen--------------------------------------------------------------------- Adresse Address1("Denny","Fischer","fuckweg","8","08484-234"); Adresse Address2("Heid","Stefan","langweg","23","08484-297"); Adresse Address3("Schoeninger","Sebastian","kurzweg","4","0848-1984"); std::cout<<"3 Adressen in Objekt einfuegen..."<<std::endl; Freunde.einfuegen(Address1); Freunde.einfuegen(Address2); Freunde.einfuegen(Address3); //--speichern--------------------------------------------------------------------- std::cout<<std::endl<<"speichern..."<<std::endl; Freunde.savetofile(dateiname); //--ausgeben---------------------------------------------------------------------- std::cout<<std::endl<<"ausgeben auf console..."<<std::endl; Freunde.ausgabe(); //--sortieren--------------------------------------------------------------------- std::cout<<std::endl<<"sortieren..."<<std::endl; Freunde.sortieren(); //--ausgeben---------------------------------------------------------------------- std::cout<<std::endl<<"ausgeben auf console (sortiert)..."<<std::endl; Freunde.ausgabe(); //--loeschen---------------------------------------------------------------------- std::cout<<std::endl<<"loeschen...dann leere liste ausgeben..."<<std::endl; Freunde.loeschen(); Freunde.ausgabe(); //--laden------------------------------------------------------------------------- std::cout<<std::endl<<"laden von file..."<<std::endl; Freunde.loadfromfile(dateiname); //--ausgeben---------------------------------------------------------------------- std::cout<<std::endl<<"geladene lsite ausgeben..."<<std::endl; Freunde.ausgabe(); getchar(); return 0; } //--------------------------------------------------------------------------------//adresse.h------------------------------------------------------------------- #ifndef adresseH #define adresseH #include <string> #include <iostream> class Adresse { std::string name; std::string vorname; std::string street; std::string hausnr; std::string phone; public: Adresse( std::string name="", std::string vorname="", std::string street="", std::string hausnr="", std::string phone="") : name(name), vorname(vorname), street(street), hausnr(hausnr), phone(phone) {} friend std::ostream& operator<<(std::ostream& outstream, Adresse const & adresse); friend std::istream& operator>>(std::istream& instream, Adresse const & adresse); friend bool sortname(const Adresse &a, const Adresse &b); }; //--------------------------------------------------------------------------- #endif//adresse.cpp---------------------------------------------------------------- #include "adresse.h" #include <string> #include <iostream> std::ostream& operator<<(std::ostream& outstream, Adresse const & adresse) { outstream << adresse.name << " " << adresse.vorname << " " << adresse.street << " " << adresse.hausnr << " " << adresse.phone << std::endl; return outstream; } std::istream& operator>>(std::istream& instream, Adresse const & adresse) { instream >> adresse.name; instream >> adresse.vorname; instream >> adresse.street; instream >> adresse.hausnr; instream >> adresse.phone; return instream; } bool sortname(const Adresse &a, const Adresse &b) { if(a.name < b.name)return true; else return false; } //---------------------------------------------------------------------------//adressliste.h--------------------------------------------------------------- #ifndef adresslisteH #define adresslisteH #include <deque> #include "adresse.h" class Adressliste { std::deque<Adresse> liste; std::deque<Adresse>::iterator it; public: void einfuegen(Adresse const & address); void savetofile(char const *dateiname); void loadfromfile(char const *dateiname); void sortieren(); void ausgabe(); void loeschen(); }; //--------------------------------------------------------------------------- #endif//adressliste.cpp----------------------------------------------------------------- #include "adressliste.h" #include <string> #include <iostream> #include <fstream> #include <deque> #include <algorithm> void Adressliste::einfuegen(Adresse const & address) { liste.push_back(address); } void Adressliste::savetofile(char const *dateiname) { std::fstream f; f.open(dateiname, std::ios::out); if(!f)std::cout<<"--- Fehler beim Oeffnen der Datei \"datei.txt\"! ---"<<std::endl; else { for(it= liste.begin(); it != liste.end(); ++it) f<<*it; std::cout<<"--- Liste in "<<dateiname<<" gespeichert! ---"<<std::endl; } f.close(); } void Adressliste::loadfromfile(char const *dateiname) { std::fstream f; Adresse tmp; f.open(dateiname, std::ios::in); if(!f)std::cout<<"--- Fehler beim Oeffnen der Datei \"datei.txt\"! ---"<<std::endl; else { f>>tmp; while(!f.eof()) { liste.push_back(tmp); f>>tmp; } std::cout<<"--- Liste aus "<<dateiname<<" geladen! ---"<<std::endl; f.close(); } } void Adressliste::sortieren() { std::sort(liste.begin(), liste.end(), sortname); } void Adressliste::ausgabe() { for(it= liste.begin(); it != liste.end(); ++it) std::cout<<*it; } void Adressliste::loeschen() { liste.clear(); }sobald er also von der file laden will hat er überlauf...
das programm läuft bis zum Freunde.loadfromfile(dateiname); da ist dann schluss und es kommt die fehlermeldung:
Fehlermeldung von Visual:
"Unbehandelte Ausnahme bei 0x004143e7 in adresse.exe: 0xC00000FD: Stack overflow."Mach echt keinen Spaß mehr...
-
Wann kracht es denn überhaupt? Direkt beim starten, beim schreiben, beim lesen? Bist Du mal mit dem Debugger durchgesteppt?
Ansonsten noch zwei Kleinigkeiten:
Für
if(a.name < b.name)return true; else return false;gibt es die geheime Kurzschreibweise
return a.name < b.name;Du brauchst außerdem Deine streams nicht selber schließen, das mach der Destruktor für Dich. Zum einlesen würde ich einen ifstream nehmen, zum rausschreiben einen ofstream. Außerdem ist der Vergleich mit eof möglicherweise nicht ganz das was Du willst. Ich würde die Einleseroutine etwa wie folgt schreiben:
void Adressliste::loadfromfile(char const *dateiname) { std::ifstream f(dateiname); if(!f) { std::cout<<"--- Fehler beim Oeffnen der Datei \"datei.txt\"! ---"<<std::endl; return; } for(Adresse tmp;f>>tmp;) liste.push_back(tmp); std::cout<<"--- Liste aus "<<dateiname<<" geladen! ---"<<std::endl; }
-
Jester schrieb:
Wann kracht es denn überhaupt? Direkt beim starten, beim schreiben, beim lesen? Bist Du mal mit dem Debugger durchgesteppt?
Der Überlauf muss mit der Methode loadfromfil geschehen.. wenn ich es ausklammer funktioniert das programm. Aber auch mit deiner Version gehts leider nicht und es kommt zum überlauf...
Jester schrieb:
Für
if(a.name < b.name)return true; else return false;gibt es die geheime Kurzschreibweise
return a.name < b.name;Richtig, habe ich auch schon gesehen, aber bin nicht drauf gekommen...
Danke.Jester schrieb:
Du brauchst außerdem Deine streams nicht selber schließen, das mach der Destruktor für Dich.
Wo genau schließe ich die selbst?
Jester schrieb:
Zum einlesen würde ich einen ifstream nehmen, zum rausschreiben einen ofstream. Außerdem ist der Vergleich mit eof möglicherweise nicht ganz das was Du willst. Ich würde die Einleseroutine etwa wie folgt schreiben:
void Adressliste::loadfromfile(char const *dateiname) { std::ifstream f(dateiname); if(!f) { std::cout<<"--- Fehler beim Oeffnen der Datei \"datei.txt\"! ---"<<std::endl; return; } for(Adresse tmp;f>>tmp;) liste.push_back(tmp); std::cout<<"--- Liste aus "<<dateiname<<" geladen! ---"<<std::endl; }Wie gesagt, wenn ich meinen mit deinem code ersetze habe ich das gleiche Problem.

Edit:
nach der Fehlermeldung öffnet mir visual die datei xstring
und bringt mir einen pfeil aufsize_type __CLR_OR_THIS_CALL max_size() const { // return maximum possible length of sequence size_type _Num = _Mybase::_Alval.max_size(); return (_Num <= 1 ? 1 : _Num - 1); }zudem ist mir auch nicht ganz klar was hier genau passiert:
for(Adresse tmp;f>>tmp;) liste.push_back(tmp);Könnte mir das vielleicht wer kurz erklären?
-
Wo sind denn die Fachmänner die mir sagen können warum ich bei loadfromfile(..) ein stack overflow bekomme/verursache?
Wäre echt klasse wenn mir hier einer licht ins dunkle bringt.
-
Gustl schrieb:
Wo sind denn die Fachmänner die mir sagen können warum ich bei loadfromfile(..) ein stack overflow bekomme/verursache?
Ich habe dir schon vor zwei Seiten gesagt, du solltest einen Debugger benutzen. Solche Dinge sind eigentlich deine Aufgabe. Wenn wir nicht gerade etwas im Code sehen, können wir dir auch nicht helfen. Prüf doch die Variablen auf ihre Gültigkeit. Wenn du im Debug-Mode ausführst, sollte dir die STL bei Fehlern passende Assertions liefern.
for(Adresse tmp;f>>tmp;) liste.push_back(tmp);Das funktioniert wie jede For-Schleife. Zu Beginn wird ein
Adresse-Objekt namenstmperstellt. Während der Ausdruckf>>tmpwahr ist (solange eingelesen wird und der Stream sich in einem korrekten Zustand befindet), wird an die Liste angehängt. Hier würde ich allerdings eher eine While-Schleife nehmen. Wird die Schleife durchlaufen? Endet sie?
-
Dann komme ich hier leider nicht mehr weiter, trotzdem danke.
-
Bist Du sicher, dass der Code genauso aussieht wie Du oben sagst? Mich wundert ein bißchen, dass Du eine const-Referenz im operator>> hast.
-
Gustl schrieb:
Dann komme ich hier leider nicht mehr weiter, trotzdem danke.
Nette Einstellung. Erwartest du jetzt, dass wir den Code selber versuchen zu kompilieren - in der Hoffnung, dein Verhalten zu reproduzieren und den Fehler zu lokalisieren?
Wir haben dir schon viele Hinweise gegeben, um die du dich nicht sonderlich zu kümmern scheinst. Wenn du das mit dem Debugger nicht ernst nimmst, dann kommst du eben nicht weiter. Aber du kannst mir glauben, das war nicht das letzte Problem dieser Art. Von daher würde ich mir das mit dem Debugger nochmals überlegen. Wie gesagt wären auch Konsolenausgaben ein Anfang.
-
Jester schrieb:
Bist Du sicher, dass der Code genauso aussieht wie Du oben sagst? Mich wundert ein bißchen, dass Du eine const-Referenz im operator>> hast.
Ja, genauso sieht der code aus, asc hat mir empfohlen bei operator>> const zu verwenden, da diese Übergabeparameter ja auch nicht verändert werden, ist das wohl falsch?
Nexus schrieb:
Nette Einstellung. Erwartest du jetzt, dass wir den Code selber versuchen zu kompilieren - in der Hoffnung, dein Verhalten zu reproduzieren und den Fehler zu lokalisieren?
Wir haben dir schon viele Hinweise gegeben, um die du dich nicht sonderlich zu kümmern scheinst. Wenn du das mit dem Debugger nicht ernst nimmst, dann kommst du eben nicht weiter. Aber du kannst mir glauben, das war nicht das letzte Problem dieser Art. Von daher würde ich mir das mit dem Debugger nochmals überlegen. Wie gesagt wären auch Konsolenausgaben ein Anfang.
Nein, ich möchte nicht, dass ihr den Code selbst kompiliert und mir sagt wo der genaue Fehler liegt, oder vielleicht doch? Ich habe lediglich gefragt was an diesem code falsch sein soll, fakt ist das er beim operator >> den stack overflow bringt und zwar beim Laden von einer Datei.
Aber da nicht mal Spezialisten den genauen Fehler entdecken können, sehe ich für einen Anfänger wie mich auch nicht viel Land.Ich habe gestern bestimmt 2-3h probiert und gesucht wo der Hund begraben liegt, konnte jedoch keinen fehler im code finden, zudem der teil von operator >> überladen von asc kommt... genau dort ist dieser overflow... oder zumindest dort wo er versucht von der datei mit dem operator in ein objekt zu schreiben.
Somit wächst mir die ganze Sache über den Kopf und ich warf gestern die Flinte ins Korn.
Wenn mir hierbei keiner mehr helfen kann, werde ich die Datei zeilenweise auslesen und den string zum aufteilen an einer Funktion übergeben die eine Adresse zurückgibt, somit kommt es nicht mehr zum overflow, aber ich habe die aufgabe, mit den >> operator eine datei auszulesen, leider verfehlt.
Aber es funktioniert wenigstens.
Ich danke für eure Bemühungen und werde euch mit diesem Thema auch nicht mehr belästigen.
Ich habe in diesem Thema auch viel von euch gelernt. Danke.
MfG Gustl
-
Gustl schrieb:
Jester schrieb:
Bist Du sicher, dass der Code genauso aussieht wie Du oben sagst? Mich wundert ein bißchen, dass Du eine const-Referenz im operator>> hast.
Ja, genauso sieht der code aus, asc hat mir empfohlen bei operator>> const zu verwenden, da diese Übergabeparameter ja auch nicht verändert werden, ist das wohl falsch?
Es ist nicht nur falsch, sondern wäre auch gar nicht erst kompilierbar. Beim
operator <<ist die konstante Referenz korrekt, dort wird das Objekt schliesslich nicht verändert, aber beimoperator >>veränderst du das Objekt ja. Du liesst schliesslich in das Objekt ein. Daher ist es sehr wahrscheinlich, dass du uns nicht den richtigen Code gezeigt hast. Denn der gezeigte würde nicht kompilieren und daher wäre kein Stackoverflow möglich
Grüssli
-
@ Gustl:
Es ist mir bewusst, dass es sehr demotivierend sein kann, mehrere Stunden lang einen Fehler zu suchen. Es ist auch okay, dass du hier fragst, nur können wir dir auch beim besten Willen nicht mehr gross weiterhelfen. Dazu kommt, dass der Code mit grosser Wahrscheinlichkeit nicht dem entspricht, der den Fehler erzeugt (siehe Draveres Post). Vielleicht ist es auch möglich, dass mit dem Compiler etwas nicht stimmt.Das mit dem Debugger war nur ein guter Ratschlag, der kann dir Fehlersuche massiv vereinfachen.
-

genau das const muss hier an dieser Stelle raus... dann funktioniert es, auch ohne stack overflow.
Aber ich habe euch 100pro den Orginal code gezeigt und er komiliert auch mit den const beim operator >>... unglaublich aber wahr
Jetzt habt ihr mir doch geholfen.

Thx
MfG Gustl
-
In diesem Falle gibt es nur eins: Wechsle so schnell wie möglich den Compiler.
Dass er solch fehlerhaften Code zulässt und dadurch einen Laufzeitfehler erzeugt, kann es ja nicht sein.
-
hab visual studio 2005 V2.0
dachte eigentlich schon das der gut ist...
hats einer probiert zu kompilieren?
-
Gustl schrieb:
hab visual studio 2005 V2.0
dachte eigentlich schon das der gut ist...
Wäre mir auch nicht bekannt, dass der solche Bugs hat. Tritt der Fehler bei einer Const-Referenz auch in anderen Kontexten auf?
Ansonsten kann ich Microsoft Visual C++ 2008 Express empfehlen, diese IDE finde ich sehr gut.
-
Also an anderen stellen merkt der compiler das und gibt laut...
-
Hallo zusammen,
ein paar Bemerkungen zu der Diskussion:
1. const und warum compiliert es?
Gustl hatte auf Seite 3 dieses Themas noch folgende Funktion verwendet:
[cpp]ostream& operator<<(ostream& outstream, Adresse & const adresse) [/cpp]Eine Seite später war es dann diese Version:
[cpp]std::ostream& operator<<(std::ostream& outstream, Adresse const & adresse) std::istream& operator>>(std::istream& instream, Adresse const & adresse) [/cpp]Prüfe das nochmal genau, an welcher Stelle das "const" und wo das Ampersand steht. Denn:
[cpp] Adresse & const adresse <==> Adresse & adresse aber nicht gleich: Adresse const & adresse <==> const Adresse & adresse[/cpp]Im ersten Fall ist es eine konstante Referenz (was redundant ist, denn eine Referenz ist per definitionem konstant, daher sollte man das const auch weglassen) auf Objekt vom Typ Adresse. Im zweiten Fall ist es eine Referenz auf ein konstantes Objekt.
Der erste Fall dürfte ohne Probleme kompilieren, der zweite Fall natürlich nicht.
2. Container von Objekten vs. Container von Pointern
Meiner Erfahrung nach ist es besser, nicht die Objekte selbst im Container (list, deque...) zu speichern, sondern Pointer darauf. Ist sicher Ansichtssache, hat aber einige Vorteile:
1. Die Objekte werden nur einmal erzeugt und liegen dann auf dem Heap. Beim Einfügen in den Container wird nicht das gesamte Objekt KOPIERT, sondern nur 4 Bytes eingefügt.
2. Der Container selbst bleibt klein, da er ja nur den Pointer dazukriegt. Sollten also Elemente zum Container dazukommen, sich ändern oder gelöscht werden, kann die Operation schnell erfolgen, andernfalls muss nämlich der komplette Container (mit allen Objekten drin) im Speicher verschoben oder umorganisiert werden. Bei Pointern bleiben die Objekte, wo sie sind, und der Container bleibt klein.
3. Objekte werden genau dann erzeugt, wenn man sie braucht. Fixe Objekte wie Adresse1, Adresse2, Adresse3 sind ja später nicht vorgesehen, und auch der Code der Ladefunktion[cpp] for(Adresse tmp;f>>tmp;) liste.push_back(tmp);[/cpp]ergeugt ein Objekt zu viel (das letzte nämlich). Auch wenn es gleich wieder gelöscht wird, sollte das nicht geschehen.
Wie wäre es daher mit diesem:
[cpp]// in adressliste.h: typedef std::deque< Adresse* > liste_t; // nur ein anderer Name, leichter zu benutzen... liste_t liste; // adressliste.cpp: int Adressliste::loadfromfile( char const *dateiname ) { .... while( ! f.eof( ) ) { Adresse* pAdresse = new adresse; // <-- Das Objekt wird erst hier erzeugt f >> *pAdresse; liste.push_back( pAdresse ); }[/cpp]Jetzt werden exakt so viele Adressen erzeugt wie benötigt, und zwar schön kompakt alles innerhalb der while-Schleife. Später benutzt man die Liste wie gehabt, verwendet dann einfach -> statt . wenn man auf ein Element zugreifen will.
3. For each
Die for_each( ) -Schleife hat leider den Nachteil, dass ihre Benutzung so sehr anderes ist als die normale for( )-Schleife: Man braucht immer noch ein Funktionsobjekt, in dem die eigentliche Arbeit getan wird. Dadurch wird der Funktionsblock und der ausgeführte Code auseinandergerissen. Ich benutze daher gerne folgendes Makro (egal ob global oder lokal definiert). Wermutstropfen ist, dass wir den Typ des Containers angeben müssen, aber den haben wir ja vorher durch das typedef schon "klein" gemacht. ITER ist wie die Laufvariable in der for( )-Schleife, nur eben ein Iterator des Containers:
[cpp]#define FOREACH(ITER, CONTAINER, TYPE) for(TYPE::iterator ITER = CONTAINER.begin(); ITER != CONTAINER.end(); ++ITER)[/cpp]Die Ausgabemethode würde damit (und mit der Pointerliste aus Abschnitt 2) so ausschauen (beachte: wir brauchen den globalen Iterator it nicht mehr! Global ist sowieso zu vermeiden).:
[cpp]void Adressliste::ausgabe( ) { FOREACH( adresse; liste; liste_t ) { std::cout << *adresse; // Beachte: ein Iterator ist ein Pointer! } }[/cpp]Oder der Destruktor für die Adressenliste. Wir brauchen ihn, da der Standard-Destruktor nur die Liste selbst mit den Pointern löscht, nicht aber die Adressen, auf die die Pointer zeigen:
[cpp]Adressliste::~Adressliste( ) { FOREACH( adresse, liste, liste_t ) { delete *adresse; } }[/cpp]4. Große Rückgabewerte von Funktionen (Code von asc):
Deine Funktion AdressenEinlesen( ) hat als Rückgabewert die komplette Liste, die - neu - in der Datei erzeugt wird. Das hat einige Nachteile:
1. Bei der Rückgabe wird die gesamte Liste in die in main( ) erzeugte Liste KOPIERT. Das kann u.U. sehr aufwendig sein.
2. Was machst Du im Fall eines Fehlers, z.B. Datei ist nicht da?Es ist eleganter, die Liste nur einmal (in main) zu erzeugen und der Funktion AdressenEinlesen( ) als Referenz zu übergeben. Diese füllt dann die Adressen gleich in die Original-Liste ein (man könnte dann sogar an eine existierende Liste anhängen). Dann hast Du den Rüchgabewert frei für z.B. einen Fehlercode. Etwas so:
[cpp]int AdressenEinlesen( std::string const & dateiname, std::list<Adresse> & adressen ) { // 1. Datei Öffnen std::fstream datei(dateiname.c_str(), std::ios::in); if(datei.bad()) return -1; // <-- hier nur der Fehlercode // 2. Daten übertragen std::copy( std::istream_iterator<Adresse>(datei), // Vom Dateibegin... std::istream_iterator<Adresse>(), // ...bis kein Eintrag mehr existiert std::back_insert_iterator<std::list<Adresse> >(adressen)); // an die Liste hängen return 0; // <-- alles gutgegangen } // in main(): std::list<Adresse> adressen; int fehler = AdressenEinlesen("datei.txt", adressen); if( 0 != fehler ... [/cpp]Oder eben, wie es Gustl macht, dass das Einlesen eine Methode der Klasse Adressenliste ist...
-
O je, muss mich gleich verbessern, die Ausgabefunktion muss natürlich heißen:
[cpp]void Adressliste::ausgabe( ) { FOREACH( adresse; liste; liste_t ) { std::cout << *( *adresse ); } }[/cpp]Unser Iterator ist ja ein Pointer - auf einen Pointer - auf eine Adresse.
-
@minastaros,
Hast du getrunken? Nimmst du irgendwelche Drogen? Bist du ein Troll? Oder ist es dir mit dieser Argumentation wirklich ernst??????
Grüssli