Unbekanntes Objekt zerstören

OP #6264020
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.
Gast #6264173
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.
Gast #6264180
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.
Gast #6264182
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
Gast #6264196
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).
#6264231
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.
Gast #6264250
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren