1

看看这三个类(包括省略):

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

如果您问我,根据对齐方式,要么AB必须具有与C. 但是,以其他方式打印sizeof声明:

A: 16
B: 16
C: 8

为什么会这样?

4

1 回答 1

5

通过 C++11,9/4:

类类型的完整对象和成员子对象应具有非零大小。

只要每个对象都有一唯一的类型和地址,就没有这样的限制适用于基类。因此,只要“第一个”数据成员与基本子对象的类型不同,则基本子对象的大小可能为零,既不完整也不是成员。

(我把“第一”放在引号中,因为涉及访问级别的复杂性。)

事实上,1.8/5-6 形式化了上述内容:

5 除非它是位域 (9.6),否则最派生对象应具有非零大小并应占用一个或多个字节的存储空间。基类子对象的大小可能为零。普通可复制或标准布局类型(3.9)的对象应占用连续的存储字节。

6 除非对象是位域或大小为零的基类子对象,否则该对象的地址是它占用的第一个字节的地址。如果一个对象是另一个的子对象,或者如果至少一个是大小为零的基类子对象并且它们属于不同类型,则两个不是位域的对象可能具有相同的地址;否则,它们应具有不同的地址。


这是 的“典型”实现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 回答