为了理解我写的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
。
一些背景
在我的程序中,我将有很多的向量,似乎大多数都是空的。这意味着循环内存消耗来自空状态,即堆分配的内存不是那么重要。
一个简单的“只为这个用例”-vector很快实现了,所以我想知道我是否遗漏了任何东西,无论如何我都需要32字节的内存,即使是我自己的实现(注意 :我很可能没有实现我自己的,这只是好奇心。)
更新
我使用以下结构再次测试它:
struct Test
{
int *a, *b, *c;
std::allocator<int> alloc;
};
现在给了sizeof(Test) == 32
。似乎即使std::allocator
没有内存消耗成员(我认为),它的存在会将Test
的大小提高到32字节。
我认识到sizeof(std::allocator<int>)
会产生1
,但我认为这是编译器处理空结构的方式,并且当它被用作成员时会被优化掉。但这似乎是我编译器的一个问题。
答案 0 :(得分:2)
编译器无法优化掉空成员。标准明确禁止它。
空类类型的完整对象和成员子对象应具有非零大小
另一方面,空基类子对象的大小可能为零。这正是GCC / libstdc ++如何应对这个问题:它使向量实现继承了分配器。
答案 1 :(得分:1)
我最近遇到了同样的问题。虽然我仍然不明白 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);