C++ virtual function table Speicher Kosten
Betrachten:
class A
{
public:
virtual void update() = 0;
}
class B : public A
{
public:
void update() { /* stuff goes in here... */ }
private:
double a, b, c;
}
class C {
//Same kind of thing as B, but with different update function/data members
}
Ich bin jetzt dabei:
A * array = new A[1000];
array[0] = new B();
array[1] = new C();
//etc., etc.
Wenn ich den Anruf sizeof(B)
die zurückgegebene Größe ist die benötigte Größe von den 3 Doppel-Mitglieder, plus einige overhead erforderlich für die virtual function pointer table. Nun, zurück zu meinem code, es stellt sich heraus, dass 'sizeof(myclass)" 32; das heißt, ich bin mit 24 bytes für meine Mitglieder-Daten und 8 bytes für die virtual-function-table (4 virtuelle Funktionen). Meine Frage ist: gibt es eine Möglichkeit, kann ich optimieren? Mein Programm wird letztendlich auch verdammt viel Speicher, und ich weiß nicht wie der Klang von 25%, es wird gegessen, virtuelle Funktionen, Zeiger.
Vergessen Sie nicht-virtuellen Destruktoren.
Suchen Sie in Ihrer Strategie, sollten Sie vielleicht besser untersuchen mithilfe einer benutzerdefinierten Zuweisung von jedem
Wie die Antworten notiert, Sie zahlen nur einen pointer pro Instanz (4 bytes auf x86 und 8 bytes auf 64). Jedoch, memory-Ausrichtung ändern kann, das Bild ein wenig (zum Beispiel, wenn Sie eine Klasse mit einem char und virtuelle Methode, es dauert in der Regel 8 bytes auf x86). Auch die Microsoft C++ - Compilers hat den bekannten Fehler mit dem ausrichten der vfptr, die hinzufügen können, die 4 oder so bytes, um die Klassengröße.
Sie sollten auch Bedenken, dass da eine neue generische könnte befassen sich mit viele Arten von Objekten zuordnen können MEHR, sizeof erfordert...
Suchen Sie in Ihrer Strategie, sollten Sie vielleicht besser untersuchen mithilfe einer benutzerdefinierten Zuweisung von jedem
B
, C
usw. Mit einer grundlegenden new
für eine große Zahl von einzelnen Objekten Hinzugefügt werden kann mehr Aufwand als Sie zu realisieren.Wie die Antworten notiert, Sie zahlen nur einen pointer pro Instanz (4 bytes auf x86 und 8 bytes auf 64). Jedoch, memory-Ausrichtung ändern kann, das Bild ein wenig (zum Beispiel, wenn Sie eine Klasse mit einem char und virtuelle Methode, es dauert in der Regel 8 bytes auf x86). Auch die Microsoft C++ - Compilers hat den bekannten Fehler mit dem ausrichten der vfptr, die hinzufügen können, die 4 oder so bytes, um die Klassengröße.
Sie sollten auch Bedenken, dass da eine neue generische könnte befassen sich mit viele Arten von Objekten zuordnen können MEHR, sizeof erfordert...
InformationsquelleAutor Stewart | 2009-10-26
Du musst angemeldet sein, um einen Kommentar abzugeben.
V-Tabelle ist pro Klasse und nicht pro Objekt. Jedes Objekt enthält nur eine Zeiger, um die v-Tabelle. Also der Aufwand pro Instanz ist
sizeof(pointer)
(meist 4 oder 8 bytes). Es spielt keine Rolle, wie viele virtuelle Funktionen, die Sie für den sizeof-der Klasse object. In Anbetracht dieser, ich glaube, Sie sollten nicht sich sorgen zu viel über Sie.nur, um es hinzuzufügen - es ist immer noch eine v-Tabelle pro Klasse mit mindestens einem Zeiger pro virtueller Funktion.
Sie zahlen immer noch die zusätzlichen Kosten für die - in vielen Fällen völlig unnötig - vtable. Es füllt nur Raum pro Klasse in 'global' - bits der ausführbaren Datei, nicht pro Instanz. Sagte: der Raum kann sehr signifikant sein, insb wenn zu Erben, wenn Sie nicht brauchen, um, aus den Klassen w/ hohe zahlen von virtual funcs. In solchen Fällen, die Umstellung auf Zusammensetzung kann drastisch abspecken der binären. Ich abgespeckt ein Projekt ist binary durch die 1/6th durch anhalten Erben unnötig von jemandem, der Bibliothek geben. Plus es hat den üblichen Vorteil der Befreiung Ihrer Klasse design von allen anderen, gut dokumentierten Einschränkungen der Vererbung
InformationsquelleAutor Ponting
In der Regel, jede Instanz einer Klasse mit mindestens einer virtuellen Funktion wird eine zusätzliche Zeiger gespeichert, der mit seinen expliziten Daten der Mitglieder.
Es gibt keine Möglichkeit, diese Runde, aber denken Sie daran, dass (wieder typisch) jeder virtual function table ist geteilt zwischen allen Instanzen der Klasse, so ist es kein großer Aufwand, die mehrere virtuelle Funktionen oder zusätzliche Ebenen von Vererbung, sobald Sie bezahlt haben, der "vptr Steuer" (kleine Kosten der vtable-Zeiger).
Für den größeren Klassen wird der overhead viel kleiner als ein Prozent.
Wenn Sie wollen Funktionalität, die so etwas macht wie das, was virtuelle Funktionen tun, sind Sie gehen zu müssen, um es zu bezahlen, in gewisser Weise. Eigentlich mit native virtuelle Funktionen können auch die billigste option sein.
InformationsquelleAutor CB Bailey
Haben Sie zwei Möglichkeiten.
1) Don ' T worry about it.
2) nicht verwenden, virtuelle Funktionen. Allerdings nicht mit virtuellen Funktionen können bewegen Sie einfach die Größe in Ihrem code, wie Ihr code wird komplexer.
InformationsquelleAutor Roland Rabien
Den Raum Kosten für eine vtable ist ein Zeiger (modulo-Ausrichtung). Die Tabelle selbst ist nicht in jeder Instanz der Klasse.
Alignment-Probleme sind immer noch da, wenn Ihre Klasse war die Größe weniger als vtable-Zeiger, um mit zu beginnen. Sagen
struct C { char c; }
wird wahrscheinlich der Größe 1, und jede Menge solcher sind Sie dicht verpackt. Wenn Sie eine neue virtuelle Mitglied, auf einem 32-bit-Plattform wird es wahrscheinlich pad die daraus resultierende 5 chars der Lagerung zu 8, so daß Sie jetzt plötzlich habe 3 chars verschwendet pro Objekt.Diese Antwort erwähnt ausdrücklich die "Ausrichtung", und in der Tat ist dies ein problem auf Ziele mit wenig RAM (mikrocontroller). Es ist wie Pavel es beschrieben hat, noch einen char + die vtable-Zeiger (4 byte) Ergebnisse in acht Byte auf einem 32-bit-Cortex-Mx ARM (dort ist eine Polsterung von drei bytes, die wahrscheinlich/hoffentlich noch vor der vtable ptr).
InformationsquelleAutor Nikolai Fetissov
Abkehr von der nicht-Thema der vtable-Zeiger in das Objekt:
Dein code hat andere Probleme:
Das problem das slicing-problem.
Sie können nicht ein Objekt der Klasse B in einen Raum von der Größe reserviert für ein Objekt der Klasse A.
Sie gerade schneiden die B(oder C) Teil des Objekts, reinigen Sie verlassen Sie nur mit dem Teil.
Was Sie tun möchten. Ist ein array von Zeigern, so dass Sie halten jedes Element von Zeiger.
Nun haben Sie ein weiteres problem der Zerstörung. Ok. Dies könnte weiter für das Alter.
Kurze Antwort boost:: ptr_vector<>
Nie allocte array wie, es sei denn, Sie haben (zu Java-Wie, um nützlich zu sein).
Wahr. Die Waffe sprang.
InformationsquelleAutor Martin York
Wie viele Instanzen Einer abgeleiteten Klassen erwarten Sie?
Wie viele unterschiedliche A-abgeleitete Klassen erwarten Sie?
Hinweis, dass man auch mit Millionen von Instanzen, wir reden hier über eine Summe von 32 MB. Bis zu 10 Millionen, nicht Schwitzen.
In der Regel müssen Sie eine zusätzliche Zeiger pro Instanz (wenn Sie auf einem 32-bit-Plattform, die letzten 4 byte sind wegen der Ausrichtung). Jede Klasse verbraucht zusätzliche
(Number of virtual functions * sizeof(virtual function pointer) + fixed size)
bytes für seine VMT.Beachten Sie, dass, wenn man die Ausrichtung für die Doppel, sogar ein einzelnes byte als Typ-Bezeichner, wird die array-Elemente der Größe 32. So Stjepan Rajko Lösung ist hilfreich, in einigen Fällen, aber nicht in dir.
Auch nicht vergessen, dass der Aufwand für eine Allgemeine heap-für so viele kleine Objekte. Sie haben vielleicht einen anderen 8 bytes pro Objekt. Mit einem benutzerdefinierten heap-manager - wie ein Objekt/Größe bestimmten pool-Zuweisung - Sie können speichern und verwenden eine standard-Lösung.
InformationsquelleAutor peterchen
Wenn Sie gehen, um Millionen von diesen Dingen, und Speicher ist ein ernstes Anliegen für Sie, dann sollten Sie nicht zu machen Sie zu Objekten. Nur erklären, wie ein struct oder ein array von 3 Doppel - (oder was auch immer), und legen Sie die Funktionen zum Bearbeiten der Daten irgendwo anders.
Wenn Sie wirklich brauchen, das polymorphe Verhalten, können Sie wahrscheinlich nicht gewinnen, da die Art Informationen, die Sie haben würden, zu speichern, in Ihrem struct wird am Ende unter eine ähnliche Menge an Speicherplatz...
Ist es wahrscheinlich, dass Sie haben große Gruppen von Objekten, die alle vom selben Typ? In diesem Fall könnte man die Typ-Informationen eine Ebene "nach oben" aus den einzelnen "A" - Klassen...
Etwas wie:
InformationsquelleAutor Mark Bessey
Wenn Sie wissen, alle abgeleiteten Typen und Ihre jeweiligen update-Funktionen im Voraus, man könnte speichern Sie den abgeleiteten Typ in Ein und implementieren manuelle Versendung für das update-Methode.
Jedoch, wie von anderen darauf hingewiesen wird, Sie sind wirklich nicht zahlen, die viel für die vtable, und der Nachteil ist die Komplexität des Codes (und je nach Ausrichtung, Sie könnten nicht sparen Speicher!). Auch, wenn alle Ihre Mitglieder-Daten haben einen Destruktor, dann haben Sie auch sorgen über die manuelle Versendung der Destruktor.
Wenn Sie immer noch wollen, diesen Weg zu gehen, es könnte so Aussehen:
InformationsquelleAutor Stjepan Rajko
Du bist das hinzufügen einer einzigen Zeiger auf eine vtable auf jedes Objekt - wenn Sie fügen Sie mehrere neue virtuelle Funktionen die Größe jedes Objekts wird nicht erhöht. Beachten Sie, dass selbst wenn Sie auf einem 32-bit-Plattform, wo Pointer sind 4 bytes, sehen Sie die Größe des Objekts Anstieg von 8 wahrscheinlich aufgrund der Allgemeinen Ausrichtung Anforderungen der Struktur (ie., Sie sind immer 4 Byte padding).
Also selbst wenn Sie die Klasse nicht-virtuellen, indem ein einzelnes char-Mitglied würde wahrscheinlich, fügen Sie eine volle 8 bytes zu der Größe der einzelnen Objekte.
Ich denke, dass der einzige Weg, Sie werden in der Lage sein, um die Größe der Sie Objekte wäre:
InformationsquelleAutor Michael Burr
Nicht eine Antwort auf die Frage nicht direkt, aber bedenkt auch, dass die Erklärung, um Ihre Daten-member können erhöhen oder verringern Sie Ihre real-Speicherverbrauch pro Objekt-Klasse. Dies ist, weil die meisten Compiler kann nicht (lies: nicht) Optimierung der Reihenfolge, in der die Schüler im Speicher angeordnet sind, verringern die interne Fragmentierung aufgrund der Ausrichtung leiden.
Ich würde Theke, die zwei Zeiger sind vergleichbar überträgt sich rein rechnerisch, aber C++'s Eingabe erfordert manchmal, dass Sie Stimmen. So oder so, die "compiler-magic", die gehen würden, in einem solchen system würde die berechnet werden, zu minimieren und die interne Fragmentierung der Objekte der Klasse als ganzes, nicht auf einer pro-Instanz-basis. Dies wird alle vorausgesetzt, dass ich nicht falsch verstanden Ihr Kommentar.
InformationsquelleAutor Chris Tonkinson
Wie andere schon sagten, in einem typischen gängigen Umsetzungsmöglichkeiten, einmal eine Klasse wird polymorph, jede Instanz, wächst eine Größe von einer normalen Daten-Zeiger. Es spielt keine Rolle, wie viele virtuelle Funktionen, die Sie haben in Ihrer Klasse. Auf einem 64-bit-Plattform von der Größe erhöhen würde, von 8 bytes. Wenn Sie beobachtet 8-byte-Wachstum auf einem 32-bit-Plattform, die es verursacht worden sein könnte durch Polsterung Hinzugefügt, um 4-byte-Zeiger für die Ausrichtung (wenn Ihre Klasse hat 8-byte-alignment-Anforderung).
Darüber hinaus ist es wohl erwähnenswert, dass virtuelle Vererbung gelingen kann, zusätzliche Daten-Zeiger in eine Klasse Instanzen (virtual base Pointer). Ich bin nur vertraut mit ein paar Implementierungen in mindestens einer der Anzahl der virtuellen Basis-Zeiger war die gleiche wie die Anzahl der virtuellen Basen in der Klasse, was bedeutet, dass virtuelle Vererbung können potenziell mehrere interne Daten Zeiger auf die einzelnen Instanzen.
InformationsquelleAutor AnT
Angesichts all der Antworten, die sind schon hier, ich denke, ich muss verrückt sein, aber dieses scheint mir Recht sein, so bin ich Entsendung es sowieso. Als ich zum ersten mal Ihre code-Beispiel, ich dachte, Sie waren slicing die Instanzen von
B
undC
, aber dann sah ich ein wenig näher. Ich bin jetzt einigermaßen sicher, dass dein Beispiel nicht kompilieren, aber ich habe keinen compiler auf diesem Feld zu testen.Mir, das sieht aus wie die erste Zeile weist ein array von 1000
A
. Die folgenden zwei Linien betrieben, die auf die ersten und zweiten Elemente des Arrays, bzw. die Instanzen vonA
, keine Zeiger aufA
. Damit Sie nicht zuordnen einen Zeiger aufA
auf die Elemente (undnew B()
gibt wie einen Zeiger). Die Typen sind nicht gleich, somit sollte es scheitern, zur compile-Zeit (es sei dennA
eine Zuordnung Betreiber, die einenA*
, in welchem Fall es wird tun, was Sie gesagt haben, es zu tun).So, ich bin völlig off base? Ich freue mich, um herauszufinden, was ich verpasst habe.
InformationsquelleAutor rmeador
Wenn Sie wirklich wollen, um Speicher zu sparen der virtuellen Tabelle Zeiger in jedem Objekt, dann können Sie code implementieren, der im C-Stil...
E. g.
InformationsquelleAutor Ashish