如何解释sizeof(std::vector<int>)的值?

How to explain the value of sizeof(std::vector<int>)?

为了了解std::vector<int>的内存消耗我写了:

std::cout << sizeof(std::vector<int>) << std::endl;

这会产生 32。我试图了解这个价值从何而来。一些查看源代码的评论认为 std::vector 存储指针 _MyFirst_MyLast_MyEnd,这解释了 24 字节的内存消耗(在我的 64 位系统上)。

最后一个 8 字节呢?据我了解,存储的分配器不使用任何内存。这也可能是实现定义的(是吗?),所以这可能有帮助:我正在使用 MSVC 2017.5。我不保证通过查看代码找到所有成员;代码看起来很混乱。

一切似乎都很好地对齐,但答案可能如下所示吗?:Why isn't sizeof for a struct equal to the sum of sizeof of each member?。但是我用一个简单的 struct Test { int *a, *b, *c; }; 测试了它,它满足 sizeof(Test) == 24.


一些背景

在我的程序中,我会有 很多 向量,而且似乎其中大部分都是空的。这意味着临界内存消耗来自空状态,即堆分配的内存不是那么重要。

一个简单的 "just for this usecase"-vector 实现得非常快,所以我想知道我是否遗漏了什么,无论如何我都需要 32 字节的内存,即使是我自己的实现(注意:我很可能不会实现我自己的,这只是好奇)。


更新

我用下面的结构再次测试了它:

struct Test
{
    int *a, *b, *c;
    std::allocator<int> alloc;
};

现在给出 sizeof(Test) == 32。似乎即使 std::allocator 没有内存消耗成员(我认为),它的存在也会将 Test 的大小提高到 32 字节。

我认识到 sizeof(std::allocator<int>) 产生 1,但我认为这就是编译器处理空结构的方式,并且在将其用作成员时将其优化掉。但这似乎是我的编译器的问题。

std::vector 的数据成员没有标准化的东西,因此您可以假设它是实现定义的。

你提到了三个指针,因此你可以检查一个class(或一个结构)的大小,它的数据成员是三个指针。

我试过运行这个:

std::cout << sizeof(classWith3PtrsOnly) << " " << sizeof(std::vector<int>) << std::endl;

Wandbox,获得:

24 24

这几乎意味着额外的 8 个字节来自 "padding added to satisfy alignment constraints"。

编译器无法优化空成员。标准明确禁止。

Complete objects and member subobjects of an empty class type shall have nonzero size

另一方面,

空的 base class 子对象的大小可能为零。这正是 GCC/libstdc++ 解决问题的方式:它使向量实现继承分配器。

我最近也遇到了同样的问题。虽然我仍然不明白 std::vector 如何进行这种优化,但我找到了一种通过 C++20 的方法。

C++ attribute: no_unique_address (since C++20)

struct Empty {};
struct NonEmpty {
    int* p;
};

template<typename MayEmpty>
struct Test {
    int* a;
    [[no_unique_address]] MayEmpty mayEmpty;
};

static_assert(sizeof(Empty) == 1);
static_assert(sizeof(NonEmpty) == 8);

static_assert(sizeof(Test<Empty>) == 8);
static_assert(sizeof(Test<NonEmpty>) == 16);