C ++: Quelle est la taille d'un objet d'une classe vide?


111

Je me demandais quelle pouvait être la taille d'un objet d'une classe vide . Il ne peut certainement pas être de 0 octet car il devrait être possible de le référencer et de le pointer comme n'importe quel autre objet. Mais quelle est la taille d'un tel objet?

J'ai utilisé ce petit programme:

#include <iostream>
using namespace std;

class Empty {};

int main()
{
    Empty e;
    cerr << sizeof(e) << endl;
    return 0;
}

La sortie que j'ai obtenue sur les compilateurs Visual C ++ et Cygwin-g ++ était de 1 octet ! C'était un peu surprenant pour moi car je m'attendais à ce qu'il soit de la taille du mot machine (32 bits ou 4 octets).

Quelqu'un peut-il expliquer pourquoi la taille de 1 octet? Pourquoi pas 4 octets? Cela dépend-il aussi du compilateur ou de la machine? En outre, quelqu'un peut-il donner une raison plus convaincante pour laquelle un objet de classe vide ne sera pas de taille 0 octet?


Je ne vois aucune raison pour laquelle il ne pourrait pas être nul. Mais en lui donnant une taille, d'autres choses sont plus faciles dans le compilateur. Si vous disposez d'un tableau de ces éléments, chaque élément a besoin d'une adresse unique. Une taille de 1 rend cela facile.
Martin York

2
Il peut être de taille zéro s'il s'agit d'un sous-objet de classe de base.
Johannes Schaub - litb

Réponses:


129

Citant la FAQ sur le style et la technique C ++ de Bjarne Stroustrup , la raison pour laquelle la taille est différente de zéro est «Pour s'assurer que les adresses de deux objets différents seront différentes». Et la taille peut être 1 car l'alignement n'a pas d'importance ici, car il n'y a rien à regarder.


55
Bah, que diable saurait-il à propos du C ++? :-)
paxdiablo

18
@Lazer, car il n'y a pas de structures vides dans C.
aib

7
@nurabha Le pointeur this pointe vers l'objet. Il n'est pas stocké dans l'objet. Si, cependant, il existe des fonctions virtuelles, l'objet contient un pointeur vers la vtable.
tbleher le

4
@krish_oza: vous pensez mal. Lorsque vous allouez une variable sur pile, elle ne peut pas occuper zéro octet (car différentes variables nécessitent des adresses différentes), d'où la taille 1 minimum. Après cela, c'est au compilateur. De même avec new; lorsque l'espace est alloué, une autre allocation doit avoir une adresse différente. Etc. Il n'y a pas nécessairement de pointeur impliqué dans la classe vide; il peut y avoir des pointeurs vers les variables (ou des références, ou des allocations locales / de pile), mais ils ne sont pas de taille nulle et ils ne sont pas nécessairement de taille de pointeur.
Jonathan Leffler

3
@Destructor, pas plus intelligent mais je sais ce qu'est un smiley :-) Vous voudrez peut-être relire le commentaire sous cet angle et réaliser que c'était de l'humour.
paxdiablo

30

La norme stipule que la plupart des objets dérivés ont sizeof ()> = 1:

À moins qu'il ne s'agisse d'un champ de bits (class.bit), un objet le plus dérivé doit avoir une taille différente de zéro et occuper un ou plusieurs octets de mémoire. Les sous-objets de classe de base peuvent avoir une taille nulle. Objet intro ISO / CEI FDIS 14882: 1998 (F)


1
Je trouve cela difficile à croire. Le standard fait tout son possible pour s'assurer que les implémentations ont les mains libres pour faire un bon travail d'optimisation en liant les mains de l'implémenteur comme cela ne ressemble pas au genre de chose que le standard fait normalement (je peux me tromper)
Martin York

4
@eSKay - Ceci est nécessaire pour que différents objets obtiennent des adresses différentes. Vous ne pouviez pas avoir une carte de pointeurs vers des objets, par exemple, si différentes instances avaient la même adresse.
Brian Neal

14

C'est vraiment un détail de mise en œuvre. Il y a longtemps, je pensais que cela pouvait être zéro octet ou mille octets, que cela n'avait aucune incidence sur la spécification du langage. Mais, après avoir regardé la norme (section 5.3.3), sizeofest définie comme renvoyant toujours un ou plus, quoi qu'il arrive.

La taille de la classe la plus dérivée doit être supérieure à zéro.

Ceci est nécessaire, entre autres, pour vous permettre de gérer des tableaux d'objets et des pointeurs vers eux. Si vos éléments étaient autorisés à être de taille nulle, alors &(array[0])ils seraient identiques à &(array[42]), ce qui causera toutes sortes de ravages dans vos boucles de traitement.

La raison pour laquelle ce n'est peut-être pas un mot machine est qu'il n'y a pas d'éléments en son sein qui nécessitent en fait qu'il soit aligné sur une limite de mot (comme un entier). Par exemple, si vous placez char x; int y;à l'intérieur de la classe, mon GCC l'horloge à huit octets (puisque le deuxième int doit être aligné dans cette implémentation).


La raison du "pas zéro" est que différents objets doivent avoir des adresses différentes. Imaginez un tableau d'objets de taille nulle. Comment l'indexeriez-vous? Dans certains cas, le compilateur est autorisé à optimiser cela (l'optimisation de la classe de base vide)
jalf

@jalf: "Comment l'indexeriez-vous?" De la même manière que je ferais en C (pour un tableau d'objets struct, par exemple) ??
Lazer

1
@eSKay - Vous ne pourriez pas s'ils avaient une taille 0. Ils seraient tous à l'élément 0.
Brian Neal

1
@BrianNeal ce qui ne pose aucun problème, puisqu'ils n'ont aucun état pour se différencier. Les problèmes n'arrivent que lorsque vous considérez les pointeurs.
gha.st

2
Ou prendre la taille dudit tableau pour calculer sa longueur.
gha.st

6

Il y a une exception: les tableaux de longueur 0

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

int main(int argc, const char** argv) {
  std::cout << sizeof(CompletlyEmpty) << '\n';
}

Pourquoi personne n'a commenté cette réponse? Cela me semble très curieux.
Peregring-lk

Si vous créez deux objets "CompletelyEmpty" ('a' et 'b' par exemple), sizeof indique qu'ils ont une longueur de 0 octet, mais ses adresses sont différentes ('& a == & b' vaut false). Et cela devrait être impossible ... (en utilisant g ++ 4.7.2).
Peregring-lk

1
Mais si vous créez un tableau de ces objets, par exemple, c, &c[M] == &c[N]pour tous Met N(clang ++ 4.1).
Konstantin Nikitin

5
C et C ++ n'autorisent pas les tableaux de longueur nulle. Votre compilateur pourrait, mais c'est incorrect.
Konrad Borowski le

oui, la taille de la classe elle-même est égale à zéro, mais une instance de cette classe fait toujours 1 octet.
ZeR0

5

Même s'il n'est pas nécessaire d'affecter de la mémoire pour une classe vide, mais afin de créer des objets de classes vides, le compilateur affecte la mémoire minimale pouvant être affectée, qui est de 1 octet. De cette façon, le compilateur peut distinguer deux objets de la même classe vide de manière unique et pourra attribuer l'adresse de l'objet à un pointeur du type de classe vide.



3

Cela peut vous aider :-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a

La taille d'une classe ou d'une structure vide est de 1

La raison pour laquelle cela se produit se résume à une implémentation correcte du standard, l'une des choses que le standard C ++ dit est que "aucun objet ne doit avoir la même adresse en mémoire que n'importe quelle autre variable" .... Quelle est la manière la plus simple de garantir cela? Assurez-vous que tous les types ont une taille différente de zéro. Pour ce faire, le compilateur ajoute un octet factice aux structures et aux classes qui n'ont pas de membres de données et pas de fonctions virtuelles afin qu'elles aient une taille de 1 plutôt qu'une taille de 0, puis elles sont garanties d'avoir une adresse mémoire unique.


2

L'allocation de 1 octet pour une classe vide dépend du compilateur. Les compilateurs doivent s'assurer que les objets résident dans des emplacements de mémoire différents et ils doivent allouer une taille de mémoire non nulle à un objet. Écoutez les notes sur ce sujet ici: http://listenvoice.com/listenVoiceNote.aspx?id=27

Même si les compilateurs allouent une taille non nulle à une classe vide, ils effectuent également des optimisations lorsque de nouvelles classes sont dérivées de classes vides. Écoutez l'optimisation de la base vide sur les questions d'entrevue de programmation C ++ de ListenVoice.


2

la raison pour une classe sans données membres mais ayant une taille de 1 octet est que ce * texte fort * doit être stocké en mémoire afin qu'une référence ou un pointeur puisse pointer vers l'objet de cette classe


0

classe vide - cette classe ne contient aucun contenu.

toute classe qui n'est pas vide sera représentée par son contenu en mémoire.

maintenant comment la classe vide sera-t-elle représentée en mémoire? comme il n'a aucun contenu aucun moyen de montrer son existence en mémoire, mais la classe est présente, il est obligatoire de montrer sa présence en mémoire. Pour afficher la présence de classe vide dans la mémoire, 1 octet est requis.


0

Je pense que c'est le cas car 1 octet est la plus petite unité de mémoire qui peut être utilisée comme espace réservé, et elle ne peut pas donner une taille nulle car il ne sera pas possible de créer un tableau d'objets.

et le truc que vous avez dit "Cela m'a un peu surpris car je m'attendais à ce qu'il soit de la taille du mot machine (32 bits ou 4 octets)." sera vrai pour la variable de référence (mots macine) de type empty (), pas pour la taille de la classe elle-même (qui est du type de données abstrait),


0

Je pense que cette question n'a qu'un intérêt théorique mais n'a pas d'importance en pratique.

Comme déjà souligné par d'autres, dériver d'une classe vide ne fait aucun mal, car cela ne consommera pas de mémoire supplémentaire pour la partie de la classe de base.

De plus, si une classe est vide (ce qui signifie qu'elle - théoriquement - n'a pas besoin de mémoire par instance, c'est-à-dire qu'elle n'a pas de membres de données non statiques ou de fonctions membres virtuelles) alors toutes ses fonctions membres peuvent tout aussi bien (et devrait) être défini comme statique. Il n'est donc pas nécessaire de créer une instance de cette classe.

Bottom line: Si vous vous retrouvez à écrire une classe X vide, alors rendez toutes les fonctions membres statiques. Vous n'aurez alors plus besoin de créer des objets X et les classes dérivées ne seront en aucun cas affectées.


0
#include<iostream>
using namespace std;


    class Empty { };
    int main()
    {
        Empty* e1 = new Empty;
        Empty* e2 = new Empty;

        if (e1 == e2)
            cout << "Alas same address of two objects" << endl;
        else
            cout << "Okay it's Fine to have different addresses" << endl;

        return 0;
    }

Sortie: Ok, c'est bien d'avoir différentes adresses

Le renvoi de la taille 1 garantit que les deux objets n'auront pas la même adresse.


0

Il est différent de zéro pour garantir que les deux objets différents auront des adresses différentes. Différents objets doivent avoir des adresses différentes, donc la taille d'une classe vide est toujours de 1 octet.


-2

Je pense que si la taille d'une classe vide est nulle, cela signifie qu'elle n'existe pas. Pour qu'elle (classe) existe, elle nécessite d'avoir au moins 1 octet, puisque cet octet est l'adresse mémoire / référence.


-3

C'est à cause de ce pointeur, bien que le pointeur soit (entier) de 4 octets mais il se réfère à un emplacement de mémoire unique (une unité) qui est de 1 octet.


5
Désolé, mais c'est absurde.
jogojapan

@Narayan das khatri: premièrement, le type de pointeur dépend du type de données il n'est pas toujours entier et deuxièmement, la taille du pointeur dépend de la machine et du compilateur sur les machines 32 bits, c'est 4 octets et pour les machines 64 bits, c'est 8 octets.
Krishna Oza le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.