Forum: Mikrocontroller und Digitale Elektronik Unbekanntes Objekt zerstören


von Max M. (maxi123456)


Lesenswert?

C++:

Ich habe einen void pointer, indem ich ein Objekt erzeugt habe. Z.B:
1
void * p = new MeinObjekt;

Was ich bis jetzt herausfinden konnte ist, dass ich diesen vor dem 
delete casten muss. Das gelingt mir aber nicht, z.B:
1
delete (*MeinObjekt) p;

Wie mache ich das richtig? Ich benutze einen void Zeiger, weil erst zur 
Laufzeit ermittelt wird, was da mit new erzeugt wird.

Beitrag #6264076 wurde von einem Moderator gelöscht.
von 50c (Gast)


Lesenswert?

Max M. schrieb:
> Was ich bis jetzt herausfinden konnte ist, dass ich diesen vor dem
> delete casten muss.

...warum muss man "casten"?

von Pandur S. (jetztnicht)


Lesenswert?

Was willst du einen void zeiger loeschen ?

von Helios (Gast)


Lesenswert?

void heißt übersetzt "Leere", da gips nix zum Löschen

von JJ (Gast)


Lesenswert?

Auf das Subject wollte ich eigentlich antworten: "Ja haben Sie denn kein 
Dynamit?"

von Programmierer (Gast)


Lesenswert?

Der Stern ist an der falschen Stelle. Es muss lauten:
1
delete (MeinObjekt*) p;

Allerdings ist das hässlicher C-Stil. Um dem Leser zu zeigen dass hier 
eine gefährliche Operation passiert, sollte man den benannten Cast 
verwenden:
1
delete reinterpret_cast<MeinObjekt*> (p);

Objekte auf "void*" und zurück casten ist aber immer extrem hässlich und 
fehleranfällig. In guten Code macht man das fast nie. Sicher dass du das 
unbedingt brauchst?

PS: falls du einen Pointer auf die Basisklasse eines Objekts hast und 
diesen zerstören willst, muss der Destruktor der Basisklasse "virtual" 
sein, damit auch der Destruktor der abgeleiteten Klasse aufgerufen wird.

von Programmierer (Gast)


Lesenswert?

Max M. schrieb:
> Ich benutze einen void Zeiger, weil erst zur Laufzeit ermittelt wird,
> was da mit new erzeugt wird.

Klingt verkehrt. Ginge nicht auch z.B. std::variant oder klassische 
Polymorphie mit "virtual"? "void*" hat in C++ Code (fast) nichts 
verloren, das braucht man eigentlich nur für C-Interfaces und manchmal 
für I/O.

Wenn du dein Problem genauer beschreibst, kann man die bessere 
Alternativen nennen.

von robert (Gast)


Lesenswert?

Auch bei einem nicht void Pointer weist Du nie die korrekte Grösse, da 
eine abgeleitete Klasse ja grösser sein kann. Desshalb notiert sich der 
new operator vom Kompiler vor dem Pointer (den Platz hat er mit 
reserviert) die Grösse des Objektes. Der delete operator benutzt diesen 
Werte um den Speicherplatz wieder freizugeben. (beim new[] und delete[] 
funktioniert es anders)

Gruss Robert

von Blub B. (googoo)


Lesenswert?

JJ schrieb:
> Auf das Subject wollte ich eigentlich antworten: "Ja haben Sie
> denn kein Dynamit?"

Und mir kam der Ausspruch aus ,,Aliens" in den Kopf:
Ripley: “I say we take off and nuke the entire site from orbit. It’s the 
only way to be sure.” ;')

von Programmierer (Gast)


Lesenswert?

robert schrieb:
> Desshalb notiert sich der new operator vom Kompiler vor dem Pointer (den
> Platz hat er mit reserviert) die Grösse des Objektes

Das ist alles Plattform spezifisch und interessiert bei normaler 
Entwicklung nicht. Neben der Größe des freizugebenden Objekts spielt 
auch der aufzurufende Destruktor eine Rolle. Daher ist es wichtig, 
"delete" auf dem richtigen Typ aufzurufen (dem selben wie bei "new", 
oder eine Basisklasse davon wenn diese einen "virtual" Destruktor 
hat).

von Philipp Klaus K. (pkk)


Lesenswert?

Max M. schrieb:
> C++:
>
> Ich habe einen void pointer, indem ich ein Objekt erzeugt habe. Z.B:
>
>
1
> void * p = new MeinObjekt;
2
>
>
> Was ich bis jetzt herausfinden konnte ist, dass ich diesen vor dem
> delete casten muss. Das gelingt mir aber nicht, z.B:
>
>
1
> delete (*MeinObjekt) p;
2
>
>
> Wie mache ich das richtig? Ich benutze einen void Zeiger, weil erst zur
> Laufzeit ermittelt wird, was da mit new erzeugt wird.

Wenn du wirklich nicht weißt, was erzeugt wird (und die erzeugten 
Objekte auch nicht alle über eine gemeinsame Basisklasse verfügen), wird 
dir wohl nichts anderes übrig bleiben, als irgendwo zu speichern, was es 
ist.
Als C-Programmierer fällt mir dazu als ersten ein enum ein, aber 
vermutlich hat C++ da inzwischen auch schon irgend eine Alternative.

von Programmierer (Gast)


Lesenswert?

Philipp Klaus K. schrieb:
> Als C-Programmierer fällt mir dazu als ersten ein enum ein, aber
> vermutlich hat C++ da inzwischen auch schon irgend eine Alternative.

Ja, std::variant:
1
int main () {
2
  // Container für entweder classA oder class B anlegen, erstmal leer
3
  std::variant<classA, classB> v;
4
  
5
  // Instanz von classA hinein speichern
6
  v.emplace<classA> ();
7
8
  // Prüfen ob Instanz von classA gespeichert ist
9
  if (std::holds_alternative<classA> (v)) {
10
    // Instanz von classA abfragen und eine Funktion davon aufrufen
11
    std::get<classA> (v).someAFunction ();
12
  }
13
  
14
  // Die Instanz von classA durch eine Instanz von classB ersetzen. classA wird automatisch gelöscht.
15
  v.emplace<classB> ();
16
17
  // Das Objekt "v" wird beim Zurückkehren gelöscht, somit auch die jetzt enthaltene Instanz von "classB".
18
}

Dies ist typsicher, sodass man nicht versehentlich über den falschen Typ 
zugreift. Es wird automatisch der richtige Destruktur aufgerufen und man 
kann nicht am Ende einen Cast auf den falschen Typ durchführen.

https://en.cppreference.com/w/cpp/utility/variant

von Blub B. (googoo)


Lesenswert?

Max M. schrieb:
> , weil erst zur Laufzeit ermittelt wird, was da mit new erzeugt wird.

Das ist unklar. Bitte hänge das komplette Modul an deinen nächsten Post 
mit dran. Spätestens wenn du delete kompilieren willst muss klar sein 
welcher Typ das ist. Eine Idee wäre eine case-Anweisung für alle 
verschiedenen Objekttypen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.