C ++: Qual é o tamanho de um objeto de uma classe vazia?


111

Fiquei me perguntando qual poderia ser o tamanho de um objeto de uma classe vazia . Certamente não poderia ter 0 bytes, pois deveria ser possível referenciá-lo e apontar para ele como qualquer outro objeto. Mas, quão grande é esse objeto?

Usei este pequeno programa:

#include <iostream>
using namespace std;

class Empty {};

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

A saída que obtive nos compiladores Visual C ++ e Cygwin-g ++ foi de 1 byte ! Isso me surpreendeu um pouco, já que esperava que fosse do tamanho da palavra da máquina (32 bits ou 4 bytes).

Alguém pode explicar por que o tamanho de 1 byte? Por que não 4 bytes? Isso depende do compilador ou da máquina também? Além disso, alguém pode dar uma razão mais convincente de por que um objeto de classe vazio não terá o tamanho de 0 bytes?


Não vejo razão para não ser zero. Mas, ao atribuir um tamanho, as outras coisas são mais fáceis no compilador. Se você tiver uma matriz dessas coisas, cada elemento precisa de um endereço exclusivo. O tamanho 1 torna isso fácil.
Martin York,

2
Ele pode ter tamanho zero se for um subobjeto da classe base.
Johannes Schaub - litb

Respostas:


129

Citando as Perguntas frequentes sobre estilo e técnica de C ++ de Bjarne Stroustrup , o motivo pelo qual o tamanho não é zero é "Para garantir que os endereços de dois objetos diferentes sejam diferentes." E o tamanho pode ser 1 porque o alinhamento não importa aqui, já que não há nada para realmente olhar.


55
Bah, o que diabos ele sabe sobre C ++? :-)
paxdiablo

18
@Lazer, porque não há structs vazios em C.
aib 04/11/10

7
@nurabha O ponteiro this aponta para o objeto. Não é armazenado no objeto. Se, entretanto, houver funções virtuais, o objeto conterá um ponteiro para a vtable.
tbleher

4
@krish_oza: você pensa errado. Quando você aloca uma variável na pilha, ela não pode ocupar zero bytes (porque variáveis ​​diferentes precisam de endereços diferentes), portanto, o tamanho 1 é mínimo. Depois disso, cabe ao compilador. Da mesma forma com new; quando o espaço é alocado, outra alocação deve ter um endereço diferente. E assim por diante. Não há necessariamente nenhum ponteiro envolvido na classe vazia; pode haver ponteiros para as variáveis ​​(ou referências, ou alocações locais / de pilha), mas eles não têm tamanho zero e não são necessariamente o tamanho do ponteiro.
Jonathan Leffler

3
@Destructor, não é mais inteligente, mas sei o que é um smiley :-) Você pode reler o comentário sob essa luz e perceber que é humor.
paxdiablo

30

O padrão afirma que todos os objetos mais derivados têm sizeof ()> = 1:

A menos que seja um campo de bits (class.bit), um objeto mais derivado deve ter um tamanho diferente de zero e deve ocupar um ou mais bytes de armazenamento. Os subobjetos da classe base podem ter tamanho zero. ISO / IEC FDIS 14882: 1998 (E) intro.object


1
Acho isso difícil de acreditar. O padrão sai de seu caminho para garantir que as implementações tenham liberdade para fazer um bom trabalho de otimização, amarrando as mãos do implementador de forma que não soe como o tipo de coisa que o padrão normalmente faz (posso estar errado)
Martin York,

4
@eSKay - Isso é necessário para que objetos diferentes obtenham endereços diferentes. Você não poderia ter um mapa de ponteiros para objetos, por exemplo, se diferentes instâncias tivessem o mesmo endereço.
Brian Neal

14

Esse é realmente um detalhe de implementação. Uma vez, há muito tempo, pensei que poderia ser zero bytes ou mil bytes, que não tem relação com a especificação da linguagem. Mas, depois de olhar para o padrão (seção 5.3.3), sizeofé definido como sempre retornando um ou maior, não importa o quê.

O tamanho de uma classe derivada deve ser maior que zero.

Isso é necessário para, entre outras coisas, permitir que você manipule matrizes de objetos e ponteiros para eles. Se fosse permitido que seus elementos tivessem tamanho zero, &(array[0])seriam idênticos a &(array[42]), o que causaria todos os tipos de destruição em seus loops de processamento.

O motivo pelo qual pode não ser uma palavra de máquina é que não há elementos dentro dela que realmente exigem que seja alinhada em um limite de palavra (como um inteiro). Por exemplo, se você colocar char x; int y;dentro da classe, meu GCC a registra em oito bytes (já que o segundo int deve estar alinhado nessa implementação).


O motivo do "diferente de zero" é que objetos diferentes devem ter endereços diferentes. Imagine uma matriz de objetos de tamanho zero. Como você indexaria isso? Em alguns casos, o compilador tem permissão para otimizar isso (a otimização da classe base vazia)
jalf

@jalf: "Como você indexaria isso?" Da mesma forma que faria em C (para uma matriz de objetos de estrutura, por exemplo) ??
Lazer

1
@eSKay - Você não poderia se eles tivessem tamanho 0. Estariam todos no elemento 0.
Brian Neal

1
@BrianNeal o que não é problema, já que eles não têm condições de se diferenciar. Os problemas só surgem quando você considera as dicas.
gha.st

2
Ou tomando o tamanho da referida matriz para calcular seu comprimento.
gha.st

6

Há uma exceção: matrizes de comprimento 0

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

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

Por que ninguém comentou esta resposta? Parece muito curioso para mim.
Peregring-lk

Se você criar dois objetos "CompletelyEmpty" ('a' e 'b' por exemplo), sizeof diz que eles têm 0 bytes, mas seus endereços são diferentes ('& a == & b' avalia como falso). E isso deveria ser impossível ... (usando g ++ 4.7.2).
Peregring-lk

1
Mas se você criar uma matriz desta objetos, digamos, c, &c[M] == &c[N]para cada Me N(clang ++ 4.1).
Konstantin Nikitin

5
C e C ++ não permitem matrizes de comprimento zero. Seu compilador poderia, mas está incorreto.
Konrad Borowski

sim, o próprio tamanho da classe é zero, mas uma instância dessa classe ainda tem 1 byte.
ZeR0

5

Embora não seja necessário atribuir nenhuma memória para uma classe vazia, mas para fazer objetos de classes vazias, o compilador atribui a memória mínima que pode ser atribuída, que é 1 byte. Desta forma, o compilador pode distinguir dois objetos da mesma classe vazia de forma única, e será capaz de atribuir o endereço do objeto a um ponteiro do tipo de classe vazia.



3

Isso pode ajudar u :-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a

O tamanho de uma classe ou estrutura vazia é 1

A razão pela qual isso acontece resume-se à implementação adequada do padrão, uma das coisas que o padrão C ++ diz é que "nenhum objeto deve ter o mesmo endereço na memória que qualquer outra variável" ... Qual é a maneira mais fácil de garantir isso? Certifique-se de que todos os tipos tenham um tamanho diferente de zero. Para conseguir isso, o compilador adiciona um byte fictício a estruturas e classes que não têm membros de dados e funções virtuais, de forma que tenham um tamanho de 1 em vez de um tamanho de 0 e, então, é garantido que tenham um endereço de memória exclusivo.


2

A alocação de 1 byte para uma classe vazia depende do compilador. Os compiladores precisam ter certeza de que os objetos residem em diferentes locais da memória e precisam alocar um tamanho de memória diferente de zero para um objeto. Ouça as notas sobre este tópico aqui: http://listenvoice.com/listenVoiceNote.aspx?id=27

Mesmo que os compiladores aloquem um tamanho diferente de zero para uma classe vazia, eles também fazem otimizações quando novas classes são derivadas de classes vazias. Ouça sobre a otimização de base vazia nas perguntas da entrevista de programação em c ++ do ListenVoice.


2

a razão para a classe sem membros de dados, mas com tamanho de 1 byte é que este * texto forte * deve ser armazenado na memória para que uma referência ou ponteiro possa apontar para o objeto daquela classe


0

classe vazia - essa classe não contém nenhum conteúdo.

qualquer classe que não esteja vazia será representada por seu conteúdo na memória.

agora, como a classe vazia será representada na memória? como não tem conteúdo não tem como mostrar sua existência na memória, mas a classe está presente, é obrigatório mostrar sua presença na memória. Para mostrar a presença de uma classe vazia na memória, é necessário 1 byte.


0

Eu acho que é assim porque 1 byte é a menor unidade de memória que pode ser usada como um espaço reservado, e não pode dar tamanho zero, pois não será possível criar uma matriz de objetos.

e a coisa que você disse "Isso me surpreendeu um pouco, pois esperava que fosse do tamanho da palavra de máquina (32 bits ou 4 bytes)." será verdadeiro para a variável de referência (palavras macine) do tipo empty (), não o tamanho da própria classe (que é um tipo de dado abstrato),


0

Acho que essa questão é apenas de interesse teórico, mas não importa na prática.

Como já foi apontado por outros, derivar de uma classe vazia não faz mal nenhum, pois isso não consumirá nenhuma memória extra para a porção da classe base.

Além disso, se uma classe estiver vazia (o que significa que - teoricamente - não precisa de nenhuma memória por instância, ou seja, não tem nenhum membro de dados não estático ou funções de membro virtuais), então todas as suas funções de membro também podem (e deve) ser definido como estático. Portanto, não há necessidade de criar uma instância dessa classe.

Resumindo: se você estiver escrevendo uma classe X vazia, torne todas as funções-membro estáticas. Você não precisará criar objetos X, e as classes derivadas não serão afetadas de forma alguma.


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;
    }

Resultado: OK, não há problema em ter endereços diferentes

Retornar o tamanho 1 garante que os dois objetos não terão o mesmo endereço.


0

É diferente de zero para garantir que os dois objetos diferentes terão endereços diferentes. Objetos diferentes devem ter endereços diferentes, portanto, o tamanho de uma classe vazia é sempre de 1 byte.


-2

Acho que se o tamanho de uma classe vazia for zero, significa que ela não existe. Para que ele (classe) exista, é necessário ter pelo menos 1 byte, pois esse byte é o endereço de memória / referência.


-3

É por causa deste ponteiro, embora o ponteiro seja (inteiro) de 4 bytes, mas se refere a um local de memória (uma unidade) que é 1 byte.


5
Desculpe, mas isso é um absurdo.
jogojapan

@Narayan das khatri: primeiro o tipo de ponteiro depende do tipo de dados não é sempre int e segundo o tamanho do ponteiro depende da máquina e o compilador em máquinas de 32 bits é de 4 bytes e para máquinas de 64 bits é de 8 bytes.
Krishna Oza
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.