如何解释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);
为了了解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);