Speicherzugriffsfehler bei vector<>
Speicherzugriffsfehler bei vector<>
Liebe C++-Kollegen!
Zur Auswertung von Messdaten schreibe ich ein Programm, das diese zunächst einliest. Jeder eingelesene Datensatz wird in einem Objekt des Typs Dataset gespeichert. Die Datasets werden von der Hauptanwendungsklasse Cpw in einem vector <Dataset> abgelegt.
Es kompiliert nun ohne Fehler, aber zur Laufzeit gibt es Speicherzugriffsfehler, wenn ich entweder mindestens drei Datensätze lade oder wenn ich das Programm beende und mindestens zwei Datensätze geladen sind.
Ich hänge mal die Dateien cpw.cpp, cpw.h und main.cpp an.
In der Funktion parse_line() erkennt man, dass ich ein Dataset dynamisch anlege und mit setVector.push_back(*dataset) dem Vektor hinzufüge. Wenn ich in die Konsole "exit" tippe, wird außerdem setVector.clear() gemacht. Ist das nicht in Ordnung so?
Viele Grüße
Diddi
Zur Auswertung von Messdaten schreibe ich ein Programm, das diese zunächst einliest. Jeder eingelesene Datensatz wird in einem Objekt des Typs Dataset gespeichert. Die Datasets werden von der Hauptanwendungsklasse Cpw in einem vector <Dataset> abgelegt.
Es kompiliert nun ohne Fehler, aber zur Laufzeit gibt es Speicherzugriffsfehler, wenn ich entweder mindestens drei Datensätze lade oder wenn ich das Programm beende und mindestens zwei Datensätze geladen sind.
Ich hänge mal die Dateien cpw.cpp, cpw.h und main.cpp an.
In der Funktion parse_line() erkennt man, dass ich ein Dataset dynamisch anlege und mit setVector.push_back(*dataset) dem Vektor hinzufüge. Wenn ich in die Konsole "exit" tippe, wird außerdem setVector.clear() gemacht. Ist das nicht in Ordnung so?
Viele Grüße
Diddi
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Re: Speicherzugriffsfehler bei vector<>
was sagt denn der Debugger, an welcher Stelle der Fehler pasiert?
Re: Speicherzugriffsfehler bei vector<>
In C++ bist du selbst dafür verantwortlich, Objekte die du dynamisch anlegst auch wieder freizugeben.Diddi hat geschrieben: In der Funktion parse_line() erkennt man, dass ich ein Dataset dynamisch anlege und mit setVector.push_back(*dataset) dem Vektor hinzufüge. Wenn ich in die Konsole "exit" tippe, wird außerdem setVector.clear() gemacht. Ist das nicht in Ordnung so?
Das machst du hier zwar im Fehlerfall, aber nicht nachdem du das Dataset in den Vektor geschoben hast.
std::vector nimmt dir das nicht ab, bei push_back z.B. ist explizit angegeben, dass das Objekt beim Einfügen kopiert wird. Also solltest du das ursprüngliche Dataset nach dem Kopieren in den Vector auch wieder freigeben.
Das ist auf jeden Fall ein Memory Leak, muss aber nicht unbedingt für die Abstürze verantwortlich sein.
Mit einem Debugger mal nachzusehen, wo das Problem tatsächlich liegt wäre hier auf jeden Fall hilfreich.
Interessant wäre auch zu wissen, wie deine Klasse Dataset aussieht. wenn sie Pointer als Member hat musst du beim Kopieren aufpassen, dass du tatsächlich die Daten auf die der Zeiger zeigt kopierst, nicht nur den Zeiger.
- Xin
- nur zu Besuch hier
- Beiträge: 8862
- Registriert: Fr Jul 04, 2008 11:10 pm
- Wohnort: /home/xin
- Kontaktdaten:
Re: Speicherzugriffsfehler bei vector<>
Da das Projekt nicht vollständig ist, kann man im Prinzip nix nachvollziehen.Diddi hat geschrieben:Zur Auswertung von Messdaten schreibe ich ein Programm, das diese zunächst einliest. Jeder eingelesene Datensatz wird in einem Objekt des Typs Dataset gespeichert. Die Datasets werden von der Hauptanwendungsklasse Cpw in einem vector <Dataset> abgelegt.
Es kompiliert nun ohne Fehler, aber zur Laufzeit gibt es Speicherzugriffsfehler, wenn ich entweder mindestens drei Datensätze lade oder wenn ich das Programm beende und mindestens zwei Datensätze geladen sind.
Das erste, was mir auffiel - was falsch, aber nicht der Fehler ist - ist folgendes:
Code: Alles auswählen
Dataset *dataset = new Dataset();
if (dataset == NULL)
Du musst new(std::no_throw) Dataset() aufrufen, wenn Du gegen NULL (in C++ besser nullptr) prüfen möchtest oder die Exception fangen:
Code: Alles auswählen
try
{
Dataset *dataset = new Dataset();
}
catch( std::badalloc & badalloc )
{
cout << "Konnte keinen Speicher reservieren\n";
return 1;
}
Vector kopiert Dein Datenset. Das Bedeutet, dass das Datenset, dass Du mit new angelegt hast, weiterhin existiert und nie freigegeben wird.Diddi hat geschrieben:Ich hänge mal die Dateien cpw.cpp, cpw.h und main.cpp an.
In der Funktion parse_line() erkennt man, dass ich ein Dataset dynamisch anlege und mit setVector.push_back(*dataset) dem Vektor hinzufüge. Wenn ich in die Konsole "exit" tippe, wird außerdem setVector.clear() gemacht. Ist das nicht in Ordnung so?
Ich vermute den Fehler eher beim Destruktor der Klasse DataSet. Aber wissen tue ich's auch nicht.
Was sagt denn der Debugger, wo es knallt?
Noch ein Detail:
Code: Alles auswählen
setVector.push_back(*dataset);
activeSet = setVector.size() - 1;
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Re: Speicherzugriffsfehler bei vector<>
Der Debugger sagte, dass es an setVector.push_back(*dataset) scheiterte.
Ist aber nicht mehr wichtig, denn ich habe dank eurer Beiträge jetzt verstanden, dass pusch_back() das ganze Objekt kopiert. Da das natürlich nicht im Sinne des Erfinders ist, habe ich es wieder so hingedreht, wie ich es ursprünglich machen wollte, nämlich dass der setVector nur Zeiger aufnimmt:
Damit habe ich nun keine Schwierigkeiten mehr. Ich vermute, dass ich einen Kopierkonstruktor oder solches Gedöns hätte definieren müssen. Ich meine, nun einen angemessenen Destruktor von Cpw zu haben:
In der Klasse Dataset gehe ich entsprechend vor, nur dass ich dort eine Liste habe.
Xin, vielen Dank für deine Kommentare zur Exception und zur Subtraktion
Ist aber nicht mehr wichtig, denn ich habe dank eurer Beiträge jetzt verstanden, dass pusch_back() das ganze Objekt kopiert. Da das natürlich nicht im Sinne des Erfinders ist, habe ich es wieder so hingedreht, wie ich es ursprünglich machen wollte, nämlich dass der setVector nur Zeiger aufnimmt:
Code: Alles auswählen
vector<Dataset *> setVector;
...
Dataset *dataset = new Dataset();
int loadsuccess = dataset->load(word[1]);
setVector.push_back(dataset);
Code: Alles auswählen
Cpw::~Cpw()
{
for (unsigned int i = 0; i < setVector.size(); i++)
delete setVector[i];
}
Xin, vielen Dank für deine Kommentare zur Exception und zur Subtraktion
- Xin
- nur zu Besuch hier
- Beiträge: 8862
- Registriert: Fr Jul 04, 2008 11:10 pm
- Wohnort: /home/xin
- Kontaktdaten:
Re: Speicherzugriffsfehler bei vector<>
Das kann nicht schaden. Wenn Du ihn nämlich nicht definierst, baut Dir C++ einen. Der kopiert dann zum Beispiel einen Zeiger, dabei wird aber nicht garantiert, dass der Zeiger auf etwas sinnvolles zeigt - zum Beispiel wenn das ursprüngliche Objekt zerstört wird und der Destruktor auch den Speicher freigibt, auf den der Zeiger zeigt.Diddi hat geschrieben:Damit habe ich nun keine Schwierigkeiten mehr. Ich vermute, dass ich einen Kopierkonstruktor oder solches Gedöns hätte definieren müssen.
Wird nun die Kopie freigegeben, zeigt der Zeiger auf bereits freigegebenen Speicher, der dann nochmals freigegeben wird. Und das knallt dann.
Der Destruktor ist absolut in Ordnung. Drei Tipps:Diddi hat geschrieben: Ich meine, nun einen angemessenen Destruktor von Cpw zu haben:In der Klasse Dataset gehe ich entsprechend vor, nur dass ich dort eine Liste habe.Code: Alles auswählen
Cpw::~Cpw() { for (unsigned int i = 0; i < setVector.size(); i++) delete setVector[i]; }
1. Du rufst laufend size() ab. Warum?
Code: Alles auswählen
Cpw::~Cpw()
{
for (unsigned int i = 0, n = setVector.size(); i < n; i++)
delete setVector[i];
}
2. In C++ bedient man sich gerne Iteratoren, was mit 'auto' seit C++11 auch angenehmer ist:
Code: Alles auswählen
Cpw::~Cpw()
{
for (auto it=setVector.begin(), eit=setVector.end(); it!=eit; it++)
delete *it;
}
3. Wenn Du nicht gerade auf alten Compilern arbeitest, kannst Du ein Range-Loop einsetzen:
Code: Alles auswählen
Cpw::~Cpw()
{
for (Dataset * value : setVector)
delete value;
}
Wir sind doch hier, um Know-How auszutauschen.Diddi hat geschrieben:Xin, vielen Dank für deine Kommentare zur Exception und zur Subtraktion
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Re: Speicherzugriffsfehler bei vector<>
Ich empfehle hierbei ganz stark smart pointer wie std::unique_ptr. Die nehmen dir diese lästige manuelle Freigabe ab.
- Xin
- nur zu Besuch hier
- Beiträge: 8862
- Registriert: Fr Jul 04, 2008 11:10 pm
- Wohnort: /home/xin
- Kontaktdaten:
Re: Speicherzugriffsfehler bei vector<>
Womit ich ihm eigentlich auch nur recht geben kann und mich gerade frage, wieso mir das eben nicht eingefallen ist.Architekt hat geschrieben:Ich empfehle hierbei ganz stark smart pointer wie std::unique_ptr. Die nehmen dir diese lästige manuelle Freigabe ab.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.
Re: Speicherzugriffsfehler bei vector<>
Mag ja sein, dass sie bequemer sind. Ich habe es nun mal in meinem C++-Buch gelernt, nicht benötigte Objekte wieder freizugeben und finde es gar nicht so schlimm, zumal ich gerne die Zügel über die Objektverwaltung selber behalte. Außerdem scheint std::unique_ptr C++11-Standard zu sein und da mein Betriebssystem von 2011 ist, glaube ich kaum, dass mir solche zur Verfügung stehen.Architekt hat geschrieben:Ich empfehle hierbei ganz stark smart pointer wie std::unique_ptr. Die nehmen dir diese lästige manuelle Freigabe ab.
Wie gesagt, nun geht es wieder sehr gut und nachdem ich mich mit einem Funktionszeiger herumgeschlagen habe, den ich für das Sortieren einer Liste benötige (war am Ende eigentlich recht leicht), scheinen mir die größten Stolpersteine überwunden zu sein.
Re: Speicherzugriffsfehler bei vector<>
Die C++ Version hängt mit deinem Compiler zusammen und nicht mit deinem Betriebssystem...
Du kannst dir jederzeit eine neue Compiler Version herunterladen, für die Gnu Compiler Collection z.B. hier: https://gcc.gnu.org/
Du kannst dir jederzeit eine neue Compiler Version herunterladen, für die Gnu Compiler Collection z.B. hier: https://gcc.gnu.org/