Platzierung neu und Vererbung

8

Guten Abend, alle zusammen.
Ein Code-Snippet sagt mehr als tausend Worte:

%Vor%

Wie Sie sehen, möchte ich nur über die Basisklasse auf die Instanz zugreifen, ohne den Basisklassenzeiger tatsächlich zu speichern. Beachten Sie, dass im zweiten Teil die Derived2 -Typ Informationen verloren gehen, so dass ich nur mit storage und der Garantie, dass eine abgeleitete Instanz drin ist, übriggeblieben bin.

Da placement new niemals den Zielzeiger anpasst, läuft dies darauf hinaus, reinterpret_cast für die Aktualisierung auf eine Basisklasse zu verwenden. Jetzt weiß ich, dass das gefährlich ist, da der passendere static_cast den Zeiger in einigen Fällen anpasst. [1]

Und tatsächlich löst es Undefined Behavior aus. Sie finden den vollständigen Code hier auf Coliru (g ++ 4.9.0), wo er sofort zur Laufzeit abstürzt. Inzwischen ist auf meinem PC (g ++ 4.8.2) alles in Ordnung. Beachten Sie, dass die Ausgabe von beiden Zeigern vor dem Aufruf der Funktionen bei g ++ 4.9 identische Werte zeigt ... und funktioniert.

Also habe ich versucht, das Problem rückwärts zu führen: die abgeleitete Instanz so anstupsen, dass ein Zeiger auf Base gleich storage ist.

%Vor%

Kein Glück. Das Ding läuft immer noch gut bei g ++ 4.8 und fällt bei g ++ 4.9 in Flammen.

Edit: Wenn Sie darüber nachdenken, ist das obige nicht so schlau. Denn was ist, wenn die abgeleitete Instanz endet vor storage ... Autsch.

Meine Frage ist also: Gibt es eine Lösung für das, was ich erreichen möchte? Oder sind die in [1] genannten Fälle hinreichend gut definiert, dass ich Code schreiben kann, der mit einer Teilmenge von Klassen arbeitet (zB keine virtuelle Vererbung)?

    
Quentin 24.07.2014, 18:01
quelle

1 Antwort

3

Ich habe gerade Ihren Code etwas geändert, es scheint, dass reininterpret_cast nicht das Problem ist. Der Mindestcode, der diesen Fehler replizieren könnte, ist als solcher

Link zu Coliru: Ссылка

%Vor%

Die ausreichenden Bedingungen zum Auslösen dieses Fehlers sind

  1. Die Variable "storage" wird auf dem Stack als Array

  2. zugewiesen
  3. print () muss eine virtuelle Methode sein

  4. Die Compileroption sollte -O2 sein

Wenn Sie -O1 verwenden, kompiliert das Programm und läuft ohne Probleme.

Außerdem scheint dieser Fehler nur angezeigt zu werden, wenn er mit g ++ 4.9.0 kompiliert wurde. Es läuft gut, wenn mit VS2012 / 2013 oder g ++ 4.7.2 kompiliert (Sie können es auf Ссылка )

testen

Nach dem oben Gesagten zu urteilen, könnte dies ein Compiler-spezifisches Problem sein.

Hinweis: Die tatsächliche Ausgabe des in dieser Antwort angegebenen Programms unterscheidet sich von den OPs. Es zeigt keine Segmentierungsfehler an. Bei erfolgreicher Ausführung sollte jedoch "Succeed" (Erfolgreich) gedruckt werden, was bei der Ausführung auf dem Coliru nicht angezeigt wird.

Bearbeiten: Der Code wurde so geändert, dass der Fehler repliziert wurde. Keine abgeleitete Klasse benötigt.

    
Hsi-Hung Shih 27.07.2014 21:34
quelle