1

これらの 3 つのクラスを見てください (省略されたものを含む)。

template<class T> struct A {
    std::allocator<T> allocator;
    T* ptr;
};

template<class T> struct B {
    T* ptr;
    std::allocator<T> allocator;
};

template<class T> struct C : std::allocator<T> {
    T* ptr;
};

int main(int argc, char **argv) {
    std::cout << "A: " << sizeof(A<int>) << "\n";
    std::cout << "B: " << sizeof(B<int>) << "\n";
    std::cout << "C: " << sizeof(C<int>) << "\n";
}

あなたが私に尋ねると、アライメントに応じて、AまたはBと同じサイズでなければなりませんCsizeofただし、それ以外の場合はクレームを印刷します。

A: 16
B: 16
C: 8

これはなぜですか?

4

1 に答える 1

5

C++11、9/4:

クラス型の完全なオブジェクトとメンバー サブオブジェクトは、ゼロ以外のサイズを持つ必要があります。

すべてのオブジェクトが型とアドレスの一意のペアを持っている限り、そのような制限は基底クラスには適用されません。そのため、「最初の」データ メンバーが基本サブオブジェクトと同じ型を持っていない限り、基本サブオブジェクトはサイズがゼロで、完全でもメンバーでもない可能性があります。

(アクセス レベルが複雑になるため、"first" を引用符で囲みます。)

実際、1.8/5–6 は上記を形式化します。

5 ビットフィールド (9.6) でない限り、最も派生したオブジェクトはゼロ以外のサイズを持ち、1 バイト以上のストレージを占有するものとします。基本クラスのサブオブジェクトは、サイズがゼロの場合があります。簡易コピー可能または標準レイアウト タイプ (3.9) のオブジェクトは、ストレージの連続したバイトを占有する必要があります。

6 オブジェクトがサイズ 0 のビットフィールドまたは基本クラスのサブオブジェクトでない限り、そのオブジェクトのアドレスは、それが占有する最初のバイトのアドレスです。ビット フィールドではない 2 つのオブジェクトは、一方が他方のサブオブジェクトである場合、または少なくとも 1 つがサイズ 0 の基本クラス サブオブジェクトであり、それらが異なる型である場合、同じアドレスを持つことができます。それ以外の場合、それらは別個のアドレスを持つものとします。


std::vectorこれは、すべての名前マングリングを除いた の「典型的な」実装です。

template <typename T, typename Alloc>
class vector
{
    struct vbase : Alloc
    {
        T * data, * end, * capacity;
        vbase(Alloc const & a) : Alloc(a), data(), end(), capacity() { }
    };

    vbase impl;

public:
    vector(Alloc const & a = Alloc()) : impl(a) { }

    T * data() const { return impl.data; }
    T & operator[](size_t n) { return data()[n]; }

    // ...

    // use impl.allocate(), impl.construct() etc.
};

これにより、基本的にsizeof(vector<T>) == 3 * sizeof(T*)、アロケータが空になるたびに保証されます。

于 2013-10-25T22:52:35.890 に答える