probleme mit delete[]
-
Salü!
Ich habe folgendes Problem:
Ich lese eine unbestimmte Anzahl Variabeln aus einer Datenbank aus und kopiere diese danach in Arbeits-Arrays. Diese Arrays enthalten soviele Variabeln wie Einträge aus der Datenbank zurückgegeben werden. Die Deklaration ist global://Globale Deklaration AnsiString* order; AnsiString* starting_serial; AnsiString* quantity; AnsiString* assembly;
...
//Unterprogramm A order= new AnsiString[records]; starting_serial= new AnsiString[records]; quantity= new AnsiString[records]; assembly= new AnsiString[records];
...
weiterverarbeitung in diversen Unterprogrammen
...
Freigeben der Variabeln beim LogOff:void destruct_array(void){ delete[] assembly; delete[] quantity; delete[] starting_serial; delete[] order; }
Das Problem ist nun folgendes: Beim Ausloggen und erneutem Einloggen wird der Speicher vermutlich nicht wirklich freigegeben: Beim 2. Login enthält die Array alle Werte 2x, beim 3. Mal sind die Werte 3fach vorhanden usw. Wird auf einen der ungültigen Einträge zugegriffen, stürzt das Programm ab.
Wird das Programm gänzlich verlassen (z.B. mit Close(); ) funktioniert beim Neustart alles richtig.
Falls jemand sich mit ähnlichen Problemen bereits herumgeschlagen hat, währe ich froh um eine kurze Klärung. Besten Dank!
-
Hallo,
Vielleicht solltest du deine Strings gleich in einer Struktur organisieren:
Beispiel:#include <vector> //------------------- struct strPaket { AnsiString order; AnsiString starting_serial; AnsiString quantity; AnsiString assembly; }; private: strPaket* paket; // std::vector<strPaket*> Vec_paket;
Beim Abfragen eines neuen Datensatzes erstellst du eine neue Instanz dieser Struktur und die Strings werden
eingelesen.
Als Beispiel hier der Inhalt von vier Edits:Auch Beispiel: void __fastcall TForm1::Button1Click(TObject *Sender) { paket = new strPaket; paket->order = Edit1->Text; paket->starting_serial = Edit2->Text; paket->quantity = Edit3->Text; paket->assembly = Edit4->Text; Vec_paket.push_back(paket); // Ab hier Kontrolle der Daten Memo1->Lines->Clear(); for (int i = 0; i < Vec_paket.size(); i++ ) { strPaket* auslesen = Vec_paket[i]; if ( auslesen) Memo1->Lines->Add(IntToStr(i) + ": " + auslesen->order + ": " + auslesen->starting_serial + ": " + auslesen->quantity + ": " + auslesen->assembly); } }
Das Löschen der Pakete geschieht so:
int count = Vec_paket.size(); while (count) delete Vec_paket[--count];
mfg
kpeter
-
Man sollte den reservierten Speicher auch immer "leeren" z.B. mit ZeroMemory nachdem man ihn initialisiert hat.
Sonst kann es sein, dass der erneut reservierete Speicher wieder an der alten Stelle landet und er mit den alten Daten gefüttert ist...
Vielleicht hilft das...
-
Die globalen Zeigervariablen mit 0 zu intitialisieren wäre auch ganz nützlich:
[code] AnsiString* order=0; AnsiString* starting_serial=0; AnsiString* quantity=0; AnsiString* assembly=0; [/code]
Wenn dein UnterProgramm A nämlich aus irgendeinen Grund nicht aufgerufen wird, knallt es sonst, weil die Zeiger irgendwo hinzeigen.
Edit:
Auch beim Deleten würde ich die Zeiger dann auf Null setzen.
-
Hawkxxx schrieb:
Man sollte den reservierten Speicher auch immer "leeren" z.B. mit ZeroMemory nachdem man ihn initialisiert hat.
Sonst kann es sein, dass der erneut reservierete Speicher wieder an der alten Stelle landet und er mit den alten Daten gefüttert ist...
Vielleicht hilft das...
Das ist Humbug. Selbst wenn neu angeforderter Speicher Reste alter Daten enthält, was soll da passieren? Ein vernünftiges Objekt initialisiert sich selbst, sodass es einen wohldefinierten Zustand nach der Erstellung hat.
@KPeter
Gibt´s einen Grund, warum du Pointer auf Elemente statt der Elemente selbst im Vektor ablegst?@OP
Von wievielen Datensätzen reden wir denn so ungefähr? Sind es eher hunderte, Tausende oder Millionen? Wenn´s nicht gerade in die Millionen geht ist KPeters Vorschlag die richtige Wahl, ich würde ihn allerdings etwas modifizieren:#include <vector> struct MyData { AnsiString Order; AnsiString StartingSerial; AnsiString Quantity; AnsiString Assembly; MyData() { } MyData( const AnsiString& order, const AnsiString& serial, const AnsiString& qty, const AnsiString& assembly ) : Order( order ), StartingSerial( serial ), Quantity( qty ), Assembly( assembly ) { } }; using namespace std; int main() { vector<MyData> Data; Data.push_back( MyData( "order", "serial", "quantity", "assembly" ) ); }
Hier muss nirgends mehr mit delete/delete[] aufgeräumt werden, das erledigt std::vector automatisch
-
DocShoe schrieb:
@KPeter
Gibt´s einen Grund, warum du Pointer auf Elemente statt der Elemente selbst im Vektor ablegst?Nö, war wohl 'n Schnellschuss...
Deine Variante ist schon ausgereifter.
mfg
kpeter
-
Besten Dank für eure Tipps... musste leider feststellen das ich bei den Pointern in der Schule wohl ein Fensterplatz hatte. Muss mir da zuerst einmal die Grundlagen aneignen. Danach werde ich Eure Tipps auprobieren.
-
Vieles ist mur nun klarer geworden, jedoch nich ganz alles:
was genau passiert hier?
MyData() { } MyData( const AnsiString& order, const AnsiString& serial, const AnsiString& qty, const AnsiString& assembly ) : Order( order ), StartingSerial( serial ), Quantity( qty ), Assembly( assembly ) { } };
binn ich richtig in der Annahme dass du hier so etwas wie ein Zeiger auf den Speicherort jedes Strings generierst?
Ist dies nötig, um danach mit
Data.push_back( MyData( "order", "serial", "quantity", "assembly" ) );
auf die Strings zuzugreifen?
und müsste das nicht auch so gehen?
Data.Order.push_back(Form1->ADOQuery1->FieldByName("Order")->AsString;)
Wobei mir der Compiler folgende Meldung bringt:
E2316 'order' is not a member of 'vector<MyData,allocator<MyData>>'Zur gestellten Frage mit der Anzahl Datensätze: es sollte sich höchstens um Tausende handeln.
-
binn ich richtig in der Annahme dass du hier so etwas wie ein Zeiger auf den Speicherort jedes Strings generierst?
Nein. Hier werden lediglich die membervariablen deiner Klasse mit den Argumenten deines Konstruktors befüllt. Siehe Initialisierungsliste.
Zeiger sind hier nicht im Spiel.Ist dies nötig, um danach mit
...
auf die Strings zuzugreifen?Hier wird nicht zuggegriffen sondern eines neues Objekt vom Typ MyData erzeugt und dann in den Vektor gepackt.
Das Danach geht so also nicht. Immerhin erwartet der Konstruktor von MyData 4 Parameter und nicht nur einen.
-
Was manche Anfänger wohl etwas verwirrt ist die Bedeutung des Kaufmannsund (&).
Je nach Kontext ist es der addressof operator oder eine Kennzeichnung für Referenzen. Im ersten Fall erhält man einen Zeiger auf irgendetwas zurück, im zweiten Fall möchte man explizit eine Referenz auf ein bereits bestehendes Objekt haben. (const) Referenzen werden häufig bei der Parameterübergabe an Funktionen verwendet, um unnötiges Kopieren zu vermeiden.Beispiel 1: Verwendung des addressof Operators und Typkennzeichner
int A; // Fall 1 int* pointer_to_A = &A; // Fall 2 int& reference_to_A = A;
Beispiel 2: Call-by-value und Call-by-reference
// 1) Call by value void func( AnsiString somestring ) { somestring = "func"; } // 2) Call by reference void gunc( AnsiString& somestring ) { somestring = "gunc"; } // 3) Call by const-reference void hunc( const AnsiString& somestring ) { // somestring kann hier nicht modifiziert werden } int main() { // call by value: // da AnsiString einen Konstruktor hat, der eine nullterminierte Zeichenkette // erwartet und daraus einen AnsiString erzeugen kann gelingt der Funktionsaufruf // es wird ein namenloses temporäres AnsiString Objekt erzeugt und an die // Funktion func übergeben. func( "Hello World" ); // call by reference // Ähnlich wie call by value, es wird ebenfalls ein namenloses temporäres // AnsiString erzeugt und eine Referenz darauf an die Funktion gunc übergeben. // ABER: Laut Standard sind Referenzen auf temporäre Objekte nicht erlaubt, // sodass der Compiler diese Zeile nicht übersetzen sollte gunc( "Hello World" ); // Korrekt geht´s so AnsiString s = "Hello World"; gunc( s ); // call by value: // Eine Kopie des AnsiStrings s wird erzeugt und an die Funktion func übergeben. // func( s ); // call by const-reference // Genauso wie call by reference, nur dass der Standard const Referenzen auf // temporäre Objekte ausdrücklich erlaubt, damit ist der folgende Funktionsaufruf // korrekt. hunc( "Hello World" ); }
-
langsam beginne ich ein wenig zu verstehen... aber: funktioniert das nicht:
struct OrderSet { AnsiString Order; AnsiString StartingSerial; AnsiString Quantity; AnsiString Assembly; OrderSet(){ } OrderSet( const AnsiString& order, const AnsiString& serial, const AnsiString& qty, const AnsiString& assembly ) : Order(order), StartingSerial(serial), Quantity (qty), Assembly (assembly){ } };
vector<OrderSet> traced;
...
if(records>0){ //Wenn Werte zurückgegeben: j=0; //Reset Counter Variable do{ //für alle Datensätze: traced.push_back( OrderSet (Form1->ADOQuery1->FieldByName("Order")->AsString),(Form1->ADOQuery1->FieldByName("Assembly")->AsString),(Form1->ADOQuery1->FieldByName("Starting_Serial")->AsString),(Form1->ADOQuery1->FieldByName("Quantity")->AsString));//kopiere Menge Form1->ADOQuery1->Next(); //Nächster Datensatz j++; //inkrement Zählervariable }while(j<records);
Kann ich nicht direkt aus der ADO-Komponente kopieren?
Fehlermeldung des Compilers:
E2285 Could not find a match for 'OrderSet::OrderSet(AnsiString)'
-
schau dir deine Klammern mal ganz genau an, nur hinter dem letzten AsString darf eine - mit der push-back sinds dann 2 - stehen, nicht hinter den anderen, da alle Werte innerhalb der OrderSet-Klammerung stehen sollten