2010-07-30 11 views
8

Lassen Sie uns sagen, dass wir eine Klasse, die wie folgt aussieht:Speicherstruktur eines Nur-Funktion-Objekts?

class A 
{ 
    public: 
     int FuncA(int x); 
     int FuncB(int y); 

     int a; 
     int b; 
}; 

Jetzt, mit nur den beiden ints in Speicherobjekte dieser Klasse angelegt werden, ich weiß. Das heißt, wenn ich einen Vektor von Instanzen der Klasse A mache, wird es zwei ints für eine Instanz geben, gefolgt von zwei ints für die zweite Instanz usw. Die Objekte sind POD.

Aber lassen Sie uns sagen, dass die Klasse wie folgt aussieht:

class B 
{ 
    public: 
     int FuncA(int x); 
     int FuncB(int y); 
}; 

Was tun Objekte dieser Klasse aussehen wie in Erinnerung? Wenn ich einen Vektor mit Instanzen von B fülle ... was ist in dem Vektor? Mir wurde gesagt, dass nicht-virtuelle Member-Funktionen am Ende als freie Funktionen kompiliert werden, irgendwo völlig unabhängig von den Instanzen der Klasse, in der sie deklariert sind (virtuelle Funktion auch, aber die Objekte speichern eine vtable mit Funktionszeigern) . Dass die Zugriffsbeschränkungen lediglich auf der semantischen, "menschlichen" Ebene liegen. Nur die Datenelemente einer Klasse (und die vtable usw.) bilden tatsächlich die Speicherstruktur von Objekten.

Also wieder, was sehen Objekte der Klasse B im Speicher aus? Ist es eine Art Platzhalterwert? Etwas muss da sein, ich kann die Adresse des Objekts nehmen. Es muss auf etwas zeigen. Was auch immer es ist, darf der Compiler diese Objekte inline/optimieren und die Methodenaufrufe als normale freie Funktionsaufrufe behandeln? Wenn ich einen Vektor von diesen erzeuge und die gleiche Methode für jedes Objekt anrufe, kann der Compiler den Vektor eliminieren und ihn durch eine Menge normaler Aufrufe ersetzen?

Ich bin nur neugierig.

+0

Es ist mir aufgefallen, dass Sie einen Kapselungs-Wrapper für Funktionen, die * nein * Platz brauchen, verwenden könnten, Sie könnten einen Namespace anstelle einer Klasse verwenden. Alternativ, wenn Sie die Elementfunktionen statisch machen, müssen Sie niemals ein Objekt instanziieren, um auf sie zuzugreifen, so dass es keinen Platz benötigt. – Clifford

Antwort

7

Alle Objekte in C++ haben garantiert eine Größe von> = 1, so dass jedes Objekt eine eindeutige Adresse hat.

Ich habe es nicht versucht, aber ich würde vermuten, dass in Ihrem Beispiel der Compiler 1 Byte für jedes Funktionsobjekt im Array/Vektor zuweisen, aber nicht initialisieren würde.

4

Wie sehen Objekte dieser Klasse im Speicher aus?

Es ist völlig auf den Compiler. Eine Instanz einer leeren Klasse muss eine Größe ungleich Null haben, so dass unterschiedliche Objekte unterschiedliche Adressen haben (es sei denn, sie werden als Basisklasse einer anderen Klasse instanziiert, in diesem Fall kann sie überhaupt keinen Platz einnehmen). Normalerweise besteht es aus einem einzelnen nicht initialisierten Byte.

Was auch immer es ist, darf der Compiler diese Objekte inline/optimieren und die Methodenaufrufe als normale freie Funktionsaufrufe behandeln?

Ja; Der Compiler muss das Objekt nicht erstellen, es sei denn, Sie machen etwas wie die Adresse. Leere Funktionsobjekte werden in der Standardbibliothek häufig verwendet. Daher ist es wichtig, dass sie keinen unnötigen Overhead verursachen.

0

Alles, was ich von hier aus sage, ist implementierungsabhängig - aber die meisten Implementierungen werden übereinstimmen.

Wenn die Klasse über virtuelle Methoden verfügt, wird ein unsichtbares vtable-Zeigerelement vorhanden sein.Das ist bei deinem Beispiel jedoch nicht der Fall.

Ja, der Compiler behandelt einen Mitgliedsfunktionsaufruf genauso wie einen freien Funktionsaufruf, es sei denn, es handelt sich um eine virtuelle Funktion. Auch wenn es sich um eine virtuelle Funktion handelt, kann der Compiler die vtable umgehen, wenn er zum Zeitpunkt des Aufrufs den konkreten Typ kennt. Jeder Aufruf hängt immer noch vom Objekt ab, da ein unsichtbarer this Parameter mit dem Objektzeiger vorhanden ist, der dem Aufruf hinzugefügt wird.

2

Ich führte das folgende Experiment:

#include <iostream> 

class B 
{ 
    public: 
     int FuncA(int x); 
     int FuncB(int y); 
}; 

int main() 
{ 
    std::cout << sizeof(B) ; 
} 

Das Ergebnis war 1 (VC++ 2010)

Es scheint mir, dass die Klasse tatsächlich erfordert keinerlei Erinnerung, sondern, dass ein Objekt nicht Null Größe sein kann denn das würde keinen semantischen Sinn ergeben, wenn du zum Beispiel seine Adresse genommen hättest. Dies wird durch Ferruccios Antwort bestätigt.

5

Wie Ferruccio sagte, haben alle Objekte in C++ garantiert eine Größe von mindestens 1. Größtenteils wahrscheinlich ist es 1 Byte, aber füllt die Größe der Ausrichtung aus, aber was auch immer .

Wenn jedoch als Basisklasse verwendet werden, es braucht keinen Raum zu füllen, so dass:

class A {} a; // a is 1 byte. 
class B {} b; // b is 1 byte. 
class C { A a; B b;} c; // c is 2 bytes. 
class D : public A, B { } d; // d is 1 byte. 
class E : public A, B { char ee; } e; // e is only 1 byte 
0

ich denke, dass sie wie alle Objekte in C anschauen ++:

  • Jede Instanz der Klasse belegt Platz. Da Objekte in C++ eine Größe von mindestens 1 haben müssen (sie haben also eindeutige Adressen, wie Ferruccino sagte), erhalten Objekte, die keine Daten angeben, keine spezielle Behandlung.
  • Nicht-virtuelle Funktionen belegen in einer Klasse überhaupt keinen Platz. Vielmehr können sie so gedacht als Funktionen werden:

    int B_FuncA(B *this, int x); 
    int B_FuncB(B *this, int y); 
    

Wenn diese Klasse kann von anderen .cpp-Dateien verwendet werden, denke ich, diese Instanzen eigentliche Klasse werden wird, nicht reguläre Funktionen.

Wenn Sie nur möchten, dass Ihre Funktionen frei und nicht an Objekte gebunden sind, können Sie entweder make them static oder use a namespace.

0

Mir wurde gesagt, dass nicht-virtuelle Elementfunktionen am Ende als freie Funktionen kompiliert werden irgendwo völlig unabhängig von den Instanzen der Klasse, in der sie deklariert werden (virtuelle Funktion sind auch, aber die Objekte speichern eine vtable mit Funktionszeigern). Dass die Zugriffsbeschränkungen lediglich auf der semantischen, "menschlichen" Ebene liegen. Nur die Datenelemente einer Klasse (und die vtable usw.) bilden tatsächlich die Speicherstruktur von Objekten.

Ja, das ist normalerweise, wie es funktioniert. Es lohnt sich vielleicht, auf die Unterscheidung hinzuweisen, dass dies nicht im Standard spezifiziert ist, und es ist nicht erforderlich - es macht nur Sinn, solche Klassen im Compiler zu implementieren.

Also wieder, wie sehen Objekte der Klasse B im Speicher aus? Ist es eine Art Platzhalterwert?Etwas muss da sein, ich kann die Adresse des Objekts nehmen

Genau. :) Der C++ - Standard erfordert, dass Objekte mindestens ein Byte belegen, genau aus dem Grund, den Sie sagen. Es muss eine Adresse haben, und wenn ich diese Objekte in ein Array setze, muss ich in der Lage sein, einen Zeiger zu inkrementieren, um "das nächste" Objekt zu bekommen, so dass jedes Objekt eine eindeutige Adresse haben muss und mindestens 1 Byte braucht. (Natürlich haben leere Objekte nicht , um genau 1 Byte zu nehmen. Einige Compiler können aus Leistungsgründen 4 Bytes oder jede andere Größe wählen)

Ein vernünftiger Compiler wird es nicht einmal schaffen ein Platzhalterwert jedoch. Warum sollte man einen bestimmten Wert in dieses eine Byte schreiben? Wir können es einfach den Müll enthalten lassen, der beim Erstellen des Objekts enthalten war. Es wird sowieso nie zugegriffen werden. Ein einzelnes Byte wird nur zugewiesen und niemals gelesen oder geschrieben.

Verwandte Themen