C ++ : 빈 클래스의 개체 크기는 얼마입니까?


111

빈 클래스의 객체의 크기 가 얼마인지 궁금합니다 . 다른 객체처럼 참조하고 가리킬 수 있어야하므로 0 바이트가 될 수 없습니다 . 그러나 그러한 물체는 얼마나 큰가요?

이 작은 프로그램을 사용했습니다.

#include <iostream>
using namespace std;

class Empty {};

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

Visual C ++ 및 Cygwin-g ++ 컴파일러에서 얻은 출력은 1 바이트 였습니다 ! 기계어 크기 (32 비트 또는 4 바이트) 크기가 될 것으로 예상했기 때문에 이것은 나에게 조금 놀랐습니다.

누구든지 1 바이트 크기 인지 설명 할 수 있습니까 ? 4 바이트가 아닌 이유는 무엇 입니까? 이것은 컴파일러 또는 기계에도 의존합니까? 또한 누군가가 빈 클래스 객체 의 크기가 0 바이트 가 아닌 이유에 대해 더 합리적인 이유를 줄 수 있습니까?


0이 될 수없는 이유가 없습니다. 그러나 크기를 지정하면 컴파일러에서 다른 작업이 더 쉽습니다. 이러한 배열이있는 경우 각 요소에는 고유 한 주소가 필요합니다. 1의 크기는 이것을 쉽게 만듭니다.
Martin York

2
기본 클래스 하위 개체 인 경우 크기가 0 일 수 있습니다.
Johannes Schaub-litb

답변:


129

Bjarne Stroustrup의 C ++ Style and Technique FAQ를 인용 하면 크기가 0이 아닌 이유는 "두 개의 다른 객체의 주소가 달라 지도록하기 위해서"입니다. 그리고 실제로 볼 것이 없기 때문에 여기서 정렬은 중요하지 않기 때문에 크기는 1이 될 수 있습니다.


55
Bah, 그가 C ++에 대해 뭘 알 겠어요? :-)
paxdiablo

18
@Lazer, C에 빈 구조체가 없기 때문입니다.
aib

7
@nurabha this 포인터 는 개체 가리 킵니다 . 개체에 저장되지 않습니다. 그러나 가상 함수가있는 경우 개체에는 vtable에 대한 포인터가 포함됩니다.
tbleher

4
@krish_oza : 당신은 잘못 생각합니다. 스택에 변수를 할당 할 때 변수는 0 바이트를 차지할 수 없습니다 (다른 변수에는 다른 주소가 필요하기 때문). 따라서 크기는 최소 1입니다. 그 후에는 컴파일러에 달려 있습니다. 마찬가지로 new; 공간이 할당 될 때 다른 할당은 다른 주소를 가져야합니다. 등등. 빈 클래스와 관련된 포인터가 반드시 필요한 것은 아닙니다. 변수 (또는 참조 또는 로컬 / 스택 할당)에 대한 포인터가있을 수 있지만 크기가 0이 아니며 반드시 포인터 크기가 아닙니다.
Jonathan Leffler 2014

3
@Destructor, 영리하지는 않지만 스마일리가 무엇인지 압니다 :-) 그 관점에서 주석을 다시 읽고 그것이 유머임을 깨달을 수 있습니다.
paxdiablo

30

표준에 따르면 대부분의 파생 객체는 sizeof ()> = 1입니다.

비트 필드 (class.bit)가 아니면 대부분의 파생 객체는 0이 아닌 크기를 가져야하며 하나 이상의 저장 공간을 차지해야합니다. 기본 클래스 하위 개체의 크기는 0 일 수 있습니다. ISO / IEC FDIS 14882 : 1998 (E) intro.object


1
나는 그것을 믿기 어렵다는 것을 안다. 표준은 표준이 일반적으로하는 일처럼 들리지 않는 것처럼 구현 자의 손을 묶어 최적화 작업을 수행 할 자유가 있는지 확인하기 위해 그 방법을 벗어납니다 (나는 틀릴 수 있습니다)
마틴 뉴욕

4
@eSKay-다른 개체가 다른 주소를 갖도록하기 위해 필요합니다. 예를 들어 서로 다른 인스턴스가 동일한 주소를 가진 경우 개체에 대한 포인터 맵을 가질 수 없습니다.
Brian Neal

14

이것은 실제로 구현 세부 사항입니다. 오래 전, 나는 그것이 언어 사양과 무관 한 0 바이트 또는 천 바이트 일 수 있다고 생각했습니다. 그러나 표준 (섹션 5.3.3)을 살펴본 후에 sizeof는 무엇이든지 항상 하나 이상을 반환하는 것으로 정의됩니다.

가장 많이 파생 된 클래스의 크기는 0보다 커야합니다.

이것은 무엇보다도 객체의 배열과 포인터를 처리 할 수 ​​있도록하기 위해 필요합니다. 요소의 크기가 0이되도록 허용 된 경우와 &(array[0])동일하게되어 &(array[42])처리 루프에 모든 종류의 혼란을 초래할 것입니다.

기계어가 아닐 수있는 이유는 단어 경계 (예 : 정수)에 실제로 정렬되어야하는 요소가 내부에 없기 때문입니다. 예를 들어, char x; int y;클래스 내부에 배치하면 내 GCC는이를 8 바이트로 클럭합니다 (두 번째 int는 해당 구현에서 정렬되어야하므로).


"0이 아님"의 이유는 다른 개체가 다른 주소를 가져야하기 때문입니다. 크기가 0 인 개체의 배열을 상상해보십시오. 어떻게 색인을 생성 하시겠습니까? 어떤 경우에는 컴파일러가이를 최적화 할 수 있습니다 (빈 기본 클래스 최적화)
jalf

@jalf : "어떻게 색인을 생성 하시겠습니까?" C에서하는 것과 같은 방식 (예 : 구조체 객체의 배열) ??
Lazer

1
@eSKay-크기가 0이면 불가능합니다. 그들은 모두 요소 0에있을 것입니다.
Brian Neal

1
@BrianNeal은 그들 자신을 차별화 할 상태가 없기 때문에 문제가되지 않습니다. 문제는 포인터를 고려할 때만 발생합니다.
gha.st

2
또는 해당 배열의 크기를 사용하여 길이를 계산합니다.
gha.st

6

예외가 있습니다. 길이가 0 인 배열

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

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

왜 아무도이 답변을 언급하지 않았습니까? 저에게는 매우 궁금해 보입니다.
Peregring-lk

두 개의 "CompletelyEmpty"객체 (예 : 'a'및 'b')를 생성하는 경우 sizeof는 길이가 0 바이트라고 말하지만 주소는 서로 다릅니다 ( '& a == & b'는 false로 평가됨). 그리고 이것은 불가능합니다 ... (g ++ 4.7.2 사용).
Peregring-lk

1
그러나이 물체, 말의 배열 작성하는 경우 c, &c[M] == &c[N]모든에 대한 MN(연타 ++ 4.1).
Konstantin Nikitin

5
C 및 C ++는 길이가 0 인 배열을 허용하지 않습니다. 컴파일러는 할 수 있지만 올바르지 않습니다.
Konrad Borowski 2013

예, 클래스 크기 자체는 0이지만이 클래스의 인스턴스는 여전히 1 바이트입니다.
ZeR0 2013-09-05

5

빈 클래스에 메모리를 할당 할 필요는 없지만 빈 클래스의 객체를 만들기 위해 컴파일러는 할당 할 수있는 최소 메모리 인 1 바이트를 할당합니다. 이런 식으로 컴파일러는 동일한 빈 클래스의 두 개체를 고유하게 구별 할 수 있으며 개체의 주소를 빈 클래스 유형의 포인터에 할당 할 수 있습니다.



3

이것은 당신을 도울 수 있습니다 :-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a

빈 클래스 또는 구조의 크기는 1입니다.

이것이 발생하는 이유는 표준을 올바르게 구현하는 것으로 귀결됩니다. C ++ 표준이 말하는 것 중 하나는 "어떤 객체도 다른 변수와 같은 메모리 주소를 가질 수 없다"는 것입니다 .... 이것을 보장하는 가장 쉬운 방법은 무엇입니까? 모든 유형의 크기가 0이 아닌지 확인하십시오. 이를 달성하기 위해 컴파일러는 데이터 멤버가없고 가상 함수가없는 구조 및 클래스에 더미 바이트를 추가하여 크기가 0이 아닌 1이되도록 한 다음 고유 한 메모리 주소를 갖도록 보장합니다.


2

빈 클래스에 1 바이트 할당은 컴파일러에 따라 다릅니다. 컴파일러는 객체가 다른 메모리 위치에 있는지 확인하고 객체에 0이 아닌 메모리 크기를 할당해야합니다. http://listenvoice.com/listenVoiceNote.aspx?id=27 에서이 주제에 대한 메모를 들어보세요.

컴파일러는 빈 클래스에 0이 아닌 크기를 할당하더라도 새 클래스가 빈 클래스에서 파생 될 때 최적화도 수행합니다. ListenVoice의 C ++ 프로그래밍 인터뷰 질문에서 빈 기본 최적화에 대해 들어보세요.


2

데이터 멤버가 없지만 크기가 1 바이트 인 클래스의 이유는 this * strong text *가 메모리에 저장되어 참조 또는 포인터가 해당 클래스의 객체를 가리킬 수 있기 때문입니다.


0

빈 클래스-해당 클래스에는 콘텐츠가 없습니다.

비어 있지 않은 클래스는 메모리의 내용으로 표시됩니다.

이제 빈 클래스가 메모리에 어떻게 표시됩니까? 메모리에 존재를 보여줄 수있는 내용이 없지만 클래스가 존재하므로 메모리에 존재를 표시해야합니다. 메모리에 빈 클래스 존재를 표시하려면 1 바이트가 필요합니다.


0

1 바이트는 플레이스 홀더로 사용할 수있는 가장 작은 메모리 단위이기 때문에 그렇다고 생각합니다. 그리고 객체 배열을 만들 수 없기 때문에 크기를 0으로 줄 수 없습니다.

"머신 워드 (32 비트 또는 4 바이트) 크기 일 것으로 예상했기 때문에 이것은 나에게 약간 놀랐습니다." 클래스 자체의 크기 (추상 데이터 유형)가 아닌 empty () 유형의 참조 변수 (macine words)에 대해 true가됩니다.


0

이 질문은 이론적으로 만 관심이 있지만 실제로는 중요하지 않습니다.

다른 사람들이 이미 지적했듯이 빈 클래스에서 파생하는 것은 기본 클래스 부분에 대한 추가 메모리를 소비하지 않기 때문에 아무런 해를 끼치 지 않습니다.

또한 클래스가 비어있는 경우 (이론적으로는 인스턴스 별 메모리가 필요하지 않습니다. 즉, 비 정적 데이터 멤버 나 가상 멤버 함수가 없음을 의미) 모든 멤버 함수도 마찬가지입니다. (그리고 반드시) 정적으로 정의되어야합니다. 따라서이 클래스의 인스턴스를 만들 필요가 없습니다.

결론 : 빈 클래스 X를 작성하는 경우 모든 멤버 함수를 정적으로 만드십시오. 그러면 X 개체를 만들 필요가 없으며 파생 클래스는 어떤 식 으로든 영향을받지 않습니다.


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

출력 : 좋습니다. 다른 주소를 사용하는 것이 좋습니다.

크기 1을 반환하면 두 개체의 주소가 동일하지 않습니다.


0

두 개의 다른 개체가 서로 다른 주소를 갖도록하는 것은 0이 아닙니다. 객체마다 주소가 달라야하므로 빈 클래스의 크기는 항상 1 바이트입니다.


-2

빈 클래스의 크기가 0이면 존재하지 않는다는 의미라고 생각합니다. 클래스 (클래스)가 존재하려면이 바이트가 메모리 / 참조 주소이므로 최소 1 바이트가 있어야합니다.


-3

포인터가 4 바이트 (정수)이지만 1 바이트 인 하나의 메모리 위치 (하나의 Unit)를 참조하지만 포인터 때문입니다 .


5
미안하지만 말도 안돼.
jogojapan 2013

@Narayan das khatri : 먼저 포인터의 유형은 데이터 유형에 따라 다르며 항상 int는 아니며 두 번째 포인터의 크기는 32 비트 머신의 머신 및 컴파일러에 따라 다르며 64 비트 머신의 경우 8 바이트입니다.
Krishna Oza 2014 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.