Ich habe eine sehr eigenartige Situation hier ... Ich habe einige alte C++ - Code (pre-C++ 11) geerbt, die lange, komplexe und die Hälfte davon ist mit geschrieben C und die andere Hälfte mit C-mit-Klassen-Mentalität (dh Klassen mit mehr Datenmitgliedern, nicht zu viele Klassenmethoden, direkte Manipulation von Datenmitgliedern ... definitiv benötigt dieses Projekt ein Refactoring, an dem ich gerade arbeite jetzt). Aber der Code deckt einige Probleme auf, die ich rätselhaft finde.Kann eine C++ - Klasseninstanziierung ihre Größe während der Laufzeit ändern
Für den Anfang wollen wir die folgenden sehr einfach nehmen (frei Fehler) Situation:
#include <iostream>
static int c = 0;
struct Bar
{
Bar() : base_id(++c) { std::cout << "Bar "<< base_id << std::endl;}
int base_id;
};
struct Foo : public Bar
{
Foo() : x(c) { std::cout << "Foo "<< x << std::endl;}
int x;
};
int main()
{
Bar* b = new Foo[200];
Foo *p;
for(p = (Foo*)b; p - (Foo*)b < 200; p ++)
{
std::cout << p->base_id << " " << ((Foo*)p)->x
<< " p-b=" << (unsigned)(p-(Foo*)b) << std::endl;
}
delete[] b;
}
oder Textversion: wir eine Reihe von Basisklassenobjekte über eine new Derived
erstellen. So weit, so gut, das ist, was die große komplexe Anwendung tut (dort sind die Klassen hierarchischer und die Konstruktoren mehr), aber die globale statische Variable (c
) ist auch in der großen komplexen Anwendung vorhanden, sie verwendet sie als eindeutiges Objekt Identifikatoren. Dann beginnt große komplexe Anwendung zu arbeiten, usw. ....
Dann zu einem bestimmten Zeitpunkt durchlaufen wir das Array von Objekten, einige Arbeit zu tun. Die Iteration sieht genauso aus wie die, die ich hier geschrieben habe, in einer for
-Schleife mit erschöpfender Zeigerarithmetik. Mein Beispiel hier druckt nur die Objekt-ID (m
) in der großen komplexen Anwendung, die mehr getan wird.
Aber irgendwo in der großen komplexen Anwendung passiert etwas Magie ... Irgendwann nach der Hälfte der Liste sind die Objekte (erhalten über die Zeiger) nicht mehr gültig, ihre base_id
s zeigen Daten, die für mich schön sind viel sieht aus wie Zeiger und andere Datenmitglieder Werte. Wenn ich jedoch die Array-Mitglieder an dem spezifischen Index überprüfe, ist der Wert dort gültig (dh: Objekt-IDs werden korrekt erhöht).
Ich habe auch die folgenden:
- Es scheint kein Problem Speicher Korruption zu sein. Valgrinds und Clang's Gedächtnis-Desinfektionsmittel zeigen keine übertriebenen Dinge.
- Alle Objekte werden ordnungsgemäß erstellt und zerstört, keine Speicherverluste.
- Der einzige Ort, an dem diese Verrücktheit ist
So ... Ich kam zu einem Abschluss in dieser Schleife über
- jemand irgendwo modifiziert einige Array-Werte tatsächlich verweisen auf verschiedene Arten von Objekt (alle von ihnen sind abgeleitet von
Bar
(e ... einige anders benannte Basisklasse) so möglicherweise muss ich mehr in den Code zu finden, um dies zu finden.Dies ist eine riesige Codebasis, gibt es buchstäblich Tausende von Referenzen für Dieses Array und davor möchte ich fragen:
(Und hier kommt die Frage :)
ich nicht bewusst bin, dass ein C++ Objekt seine Größe während der Laufzeit ändern kann (wenn es möglich ist, es mit uns bitte teilen), so neben der möglichen Ausgabe, die ich habe Hat jemand in der Community irgendwelche Ideen gefunden, warum sich diese Zeigerarithmetik so seltsam verhält?
(ja, das Projekt wird in die richtige C++ 11 mit Standardcontainern konvertiert, etc ...aber jetzt bin ich nur daran interessiert in diesem speziellen Thema)
Die Größe des Objekts wird zur Kompilierzeit berechnet. Es kann nicht in der Laufzeit geändert werden. – teivaz
"So weit, so gut" - äh, nein, du bist schon ziemlich geschraubt. Siehe hier: http://stackoverflow.com/questions/6171814/why-is-it-undefined-behavior-to-delete-an-array-of-edived-objects-via-a-base – Mat
außer den Klassen sind streng Standard-Layout, (Foo *) b wird nicht unbedingt den gleichen Wert (Adresse) wie b. Könnte das relevant sein? –