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バイトにならない理由について、より説得力のある理由を誰かが示すことができますか?


ゼロにならない理由はない。しかし、サイズを指定することで、コンパイラーで他のことが簡単になります。これらの配列がある場合、各要素には一意のアドレスが必要です。サイズが1の場合、これは簡単です。
マーティンヨーク

2
基本クラスのサブオブジェクトの場合は、サイズをゼロにすることができます。
Johannes Schaub-litb

回答:


129

Bjarne StroustrupのC ++スタイルとテクニックに関するFAQを引用する、サイズがゼロ以外である理由は、「2つの異なるオブジェクトのアドレスが確実に異なるようにするため」です。また、実際に調べる必要がないため、ここでは位置合わせは関係ないため、サイズは1にすることができます。


55
Bah、C ++について一体何を知っているのでしょうか。:-)
paxdiablo 2009年

18
@Lazer(Cには空の構造体がないため)
aib

7
このポインタ点@nurabha オブジェクト。オブジェクトには保存されません。ただし、仮想関数がある場合、オブジェクトにはvtableへのポインターが含まれます。
tbleher 2013

4
@krish_oza:あなたは間違っていると思います。スタックに変数を割り当てる場合、0バイトを占有することはできません(異なる変数には異なるアドレスが必要なため)。したがって、サイズは最小1です。その後はコンパイラ次第です。同様にnew; スペースが割り当てられるとき、別の割り当てには別のアドレスが必要です。等々。空のクラスには必ずしもポインタが含まれている必要はありません。変数へのポインタ(または参照、またはローカル/スタック割り当て)がある場合がありますが、それらはサイズがゼロではなく、必ずしもポインタサイズではありません。
ジョナサンレフラー2014

3
@Destructor、巧妙ではありませんが、スマイリーとは何かを私は知っています:-)あなたはその観点からコメントをもう一度読んで、それがユーモアだったことに気づくかもしれません。
paxdiablo 2016

30

標準では、ほとんどすべての派生オブジェクトはsizeof()> = 1であると述べています。

ビットフィールド(class.bit)でない限り、最も派生したオブジェクトはゼロ以外のサイズを持ち、1バイト以上のストレージを占有します。基本クラスのサブオブジェクトは、サイズがゼロの場合があります。 ISO / IEC FDIS 14882:1998(E)intro.object


1
それを信じるのは難しいと思います。標準は、標準が通常行うことのように聞こえないように、実装が実装者の手を縛る最適化の良い仕事をするための自由な手を持つことを確実にするために、その方法から抜け出します(私は間違っている可能性があります)
マーティンヨーク

4
@eSKay-これは、異なるオブジェクトが異なるアドレスを取得するために必要です。たとえば、異なるインスタンスが同じアドレスを持っている場合、オブジェクトへのポインタのマップを持つことができませんでした。
ブライアンニール、

14

これは実際の実装の詳細です。昔、私はそれがゼロバイトまたは千バイトであるかもしれないと思った、それが言語仕様に関係がないと。ただし、標準(セクション5.3.3)を見ると、sizeof何があっても常に1以上を返すと定義されています。

最も派生したクラスのサイズはゼロより大きくなければなりません。

これは、特に、オブジェクトの配列とそれらへのポインタを処理できるようにするために必要です。要素のサイズをゼロにできる場合、&(array[0])と同じ&(array[42])になります。これにより、処理ループにあらゆる種類の混乱が生じます。

マシンワードでない可能性があるのは、ワード境界(整数など)にアラインする必要がある要素がその中にないためです。たとえばchar x; int y;、クラス内に配置すると、GCCはそれを8バイトでクロックします(その実装では2番目のintが整列している必要があるため)。


「ゼロ以外」の理由は、オブジェクトごとにアドレスが異なる必要があるためです。サイズがゼロのオブジェクトの配列を想像してください。どのようにインデックスを付けますか?場合によっては、コンパイラはこれを最適化することを許可されます(空の基本クラスの最適化)
jalf

@jalf:「どのようにインデックスを付けますか?」Cで行うのと同じ方法(たとえば、構造体オブジェクトの配列の場合)??
Lazer、

1
@eSKay-サイズが0の場合はできませんでした。彼らはすべての要素を0にするだろう
ブライアン・ニール

1
@BrianNealは、自分自身を区別する状態がないため、問題ありません。問題は、ポインタを考慮したときにのみ発生します。
gha.st 2013年

2
または、その長さを計算するために上記の配列のサイズを取ります。
gha.st 2013年

6

例外があります:長さ0の配列

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

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

なぜ誰もこの回答にコメントしていませんか?それは私にとって非常に好奇心が強いようです。
Peregring-lk

2つの "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 2013年

5
CおよびC ++では、長さがゼロの配列は許可されていません。あなたのコンパイラは可能ですが、それは正しくありません。
Konrad Borowski 2013

はい、クラスサイズ自体はゼロですが、このクラスのインスタンスは1バイトのままです。
ZeR0 2013

5

空のクラスにメモリを割り当てる必要はありませんが、空のクラスのオブジェクトを作成するために、コンパイラは割り当て可能な最小のメモリ(1バイト)を割り当てます。このようにして、コンパイラーは同じ空のクラスの2つのオブジェクトを一意に区別でき、オブジェクトのアドレスを空のクラス型のポインターに割り当てることができます。



3

これはあなたを助けるかもしれません:-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a

空のクラスまたは構造のサイズは1です

これが発生する理由は、標準を適切に実装することになります。C++標準では、「メモリ内に他の変数と同じアドレスを持つオブジェクトはない」ということです。...これを確認する最も簡単な方法は何ですか。すべてのタイプのサイズがゼロ以外であることを確認してください。これを実現するために、コンパイラーは、データメンバーも仮想関数もない構造体とクラスにダミーバイトを追加し、サイズが0ではなく1になり、一意のメモリアドレスを持つことが保証されます。


2

空のクラスに1バイトを割り当てるかどうかは、コンパイラによって異なります。コンパイラーは、オブジェクトが異なるメモリー・ロケーションに存在することを確認する必要があり、ゼロ以外のメモリー・サイズをオブジェクトに割り当てる必要があります。このトピックに関するメモをここで聞いてください:http : //listenvoice.com/listenVoiceNote.aspx?id=27

コンパイラーはゼロ以外のサイズを空のクラスに割り当てますが、新しいクラスが空のクラスから派生する場合にも最適化を行います。ListenVoiceのc ++プログラミングインタビューの質問で空のベースの最適化について聞いてください。


2

データメンバーはないがサイズが1バイトのクラスの理由は、this * strong text *をメモリに保存して、参照またはポインターがそのクラスのオブジェクトを指すようにする必要があるためです。


0

空のクラス-そのクラスにはコンテンツが含まれていません。

空でないクラスは、メモリ内のコンテンツによって表されます。

空のクラスはどのようにメモリで表現されますか?内容がメモリに存在することを示す方法がないため、クラスが存在するため、メモリに存在を示すことが必須です。空のクラスの存在をメモリに表示するには、1バイトが必要です。


0

1バイトはプレースホルダーとして使用できる最小のメモリ単位であり、オブジェクトの配列を作成できないため、サイズをゼロにすることができないためです。

そして、あなたが言ったことは、「マシンワード(32ビットまたは4バイト)のサイズであると期待していたので、これは少し意外でした。」クラス自体のサイズ(抽象データ型)ではなく、タイプempty()の参照変数(機械語)に対して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を返すことにより、2つのオブジェクトが同じアドレスを持たないことが保証されます。


0

2つの異なるオブジェクトが異なるアドレスを持つことを保証するためにゼロ以外です。オブジェクトが異なればアドレスも異なるため、空のクラスのサイズは常に1バイトです。


-2

空のクラスのサイズがゼロの場合、それは存在しないことを意味すると思います。それ(クラス)が存在するためには、このバイトがメモリ/参照アドレスであるため、少なくとも1バイトが必要です。


-3

これは、このポインタが原因です。ただし、ポインタは4バイトの(整数)ですが、1バイトの1つのメモリロケーション(1つのユニット)を参照しています。


5
申し訳ありませんが、これはナンセンスです。
jogojapan 2013

@Narayan das khatri:最初にポインターの型はデータ型に依存しますが、常にintとは限りません。次に、ポインターのサイズは32ビットマシンのマシンとコンパイラーに依存します。4バイトで、64ビットマシンの場合は8バイトです。
クリシュナオザ2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.