Rückgabe von dynamisch erzeugten Objekten
-
Hallo Forum,
ich bin neu hier und komme aus der schön einfachen Welt der JAVA Programmierung. Diesen Nachmittag habe ich damit verbracht zu überlegen, wie ich es schaffen könnte ein Objekt mit dynamischer Klassenvariable aus einer Funktion zurückzugeben.
Hier die vereinfachte Version meines Codes (ich lasse die Header Dateien weg)://main.cpp #include <iostream> #include <string> #include "stringarray.h" int main(int argc, char **argv) { StringArray cubeFiles = getBRTFiles(CUBE_DIRECTORY); return 0; } StringArray getBRTFiles(string directory) { string directoryEntries[2]; for(unsigned int i = 0; i< 2; i++) { directoryEntries[i] = "Test"; } StringArray files(directoryEntries, 2); }Die Klasse mit dem dynamisch erzeugten Klassenelement sieht folgendermaßen aus:
#include <string> #include <iostream> #include "stringarray.h" using namespace std; /** * Konstruktor */ StringArray::StringArray(string newData[], unsigned int newLength) { cout << "Erstelle StringArray \n"; data = new string[newLength]; length = newLength; for(unsigned int i = 0; i < newLength; i++) { data[i] = newData[i]; } length = newLength; } /** * Destruktor */ StringArray::~StringArray() { cout << "StringArray wurde zerstört \n"; delete data; } /** * Überladen des = Operators um Fehler mit den dynamisch * erzeugten Objekten zu vermeiden. */ StringArray& StringArray::operator=(StringArray& array) { cout << "Objekt wird kopiert"; //Auf Selbstzuweisung überprüfen if(this == &array) { return *this; } else { length = array.length; data = new string[length]; /* for(unsigned int i = 0; i < length; i++) { data[i] = array.data[i]; }*/ return *this; } } /** * Überschreiben des kompletten Daten Arrays */ void StringArray::setData(string newData[]) { if(sizeof(data) != sizeof(newData)) { cerr << "Wrong data length for array copy \n"; } else { for(unsigned int i = 0; i < length; i++) { data[i] = newData[i]; } } } /** * Setzen eines einzelnen String Wertes im Daten Array * @param &entry Referenz auf den neuen Wert (keine Kopie nötig) */ void StringArray::setDataEntry(string &entry, unsigned int index) { data[index] = entry; } string StringArray::getDataEntry(unsigned int index) { return data[index]; }Vor Beendigung des Programms erhalte ich die Fehlermeldung:
malloc: *** error for object 0x1001001c8: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debugDas liegt daran, dass das Objekt vom Typ StringArray zweimal zerstört wird. Einmal am Ende der Funktion getBRTFiles und einmal am Ende der main Methode. Beim zweiten Zerstören zeigt data nicht mehr auf einen gültigen Speicherbereich. Ich dachte das Überladen des = Operators behebt das Problem bereits. Allerdings wird die Methode zum Überladen beim Zurückgeben des Wertes nicht aufgerufen (
cout << "Objekt wird kopiert";wird nicht ausgeführt).
Kann mir hier jemand einen Tip geben, wie ich Objekte mit dynamisch erstellten Klassenelmenten, sicher als Rückgabewerte von Funktionen verwende?
Danke
Martin
-
Hallo,
es gibt die Regel der grossen 3, die besagt, dass wenn man
Destruktor,
Copy-Ctor,
oder Zuweisungsoperatorüberschreibt, man dann alle 3 ändern muss (zumindest genau hinsehen).
So auch hier. Die Funktion getBRTFiles nutzt ja den Copy-CTor, den du nicht angepasst hast.
Es wird der default-Ctor genommen, der lediglich den Zeiger kopiert.ps.: Im Destruktor musst du dein Array mit delete[] zerstören.
-
wenn
data = new string[]dann auchdelete[] dataWarum machst du es dir nicht leichter und nimmst einen std::vector<string> und kapselst den ... dann kannst du dir das ganze new/delete gefummel spaaren

-
Hallo Euch beiden. Vielen Dank für Eure Hilfe. Gerne werd ich auf Vektoren umsteigen (die werden wohl ähnlich funktionieren wie die Verktoren in Java). Ich bin leider in meinen Fachbüchern noch nicht soweit (1000 Seiten) und ich muss mich Schritt für Schritt vorarbeiten. Vorerst hier mal der Code von Destruktor, Kopierkonstruktor und Überladen des = Operators (muss man immer machen, wenn dynamische Klassenelemente benutzt werden. Vielleicht hilfts ja jemandem:
/** * Destruktor (nötig für dynamisch erzeugte Elemente) */ StringArray::~StringArray() { cout << "StringArray wurde zerstört \n"; delete [] data; } /** * Kopierkonstruktor (nötig für dynamisch erzeugte Element) */ StringArray::StringArray(const StringArray& array2) { cout << "Kopierkonstruktor \n"; length = array2.getLength(); data = new string[length]; for(unsigned int i = 0; i < length; i++) { data[i] = array2.data[i]; } } /** * Überladen des = Operators um Fehler mit den dynamisch * erzeugten Objekten zu vermeiden. */ StringArray& StringArray::operator=(const StringArray& array) { cout << "Objekt wird kopiert"; //Auf Selbstzuweisung überprüfen if(this == &array) { return *this; } else { length = array.getLength(); data = new string[length]; for(unsigned int i = 0; i < length; i++) { data[i] = array.data[i]; } return *this; } }
-
skifidelity schrieb:
Ich bin leider in meinen Fachbüchern noch nicht soweit...
Es gibt leider viele Fachbücher die mehr C als C++ enthalten, sich aber als C++ Buch verkaufen.
-
skifidelity schrieb:
/** * Überschreiben des kompletten Daten Arrays */ void StringArray::setData(string newData[]) { if(sizeof(data) != sizeof(newData)) {Das geht so leider nicht.
newDatawird als einfacher Zeiger ansetDataübergeben,sizeof(newData)ist also abhängig vom System immer 4 bzw. 8 Bytes und nicht die Größe des Arrays. Beim Übergeben eines Arrays an eine Funktion muss immer auch dessen Länge übergeben werden, falls diese dynamisch ist.
Das Ganze kannst du dir mit einer Array-Kapselung, z.B.vectorsparen, denn der kennt seine Länge.