std::vector 的元素是否单独存储在内存中?

Men*_*iev 3 c++ stdvector

问题 :

我尝试打印向量中元素的字节数和内存地址。结果,我看到了一个内存地址和多个字节。向量的元素是单独存储的吗?如果是这样,为什么我的代码显示向量只有 24 个字节?

我尝试过的:

#include <iostream>
#include <vector>

int main(){
    std::vector<const char *> colour = {"Microsoft", "Apple", "DELL", "Accer", "Lenovo", "hp"};
    std::cout << "VectorSize : " << sizeof(colour) << "\n" << std::endl;
    for(int i = 0; i < colour.size(); i++){
        std::cout << colour[i] << " is " << sizeof(colour[i]) << " byte at " << &colour[i] << "." << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

结果 :

VectorSize : 24

Microsoft is 8 byte at 0x27b5a7c6220.
Apple is 8 byte at 0x27b5a7c6228.
DELL is 8 byte at 0x27b5a7c6230.
Accer is 8 byte at 0x27b5a7c6238.
Lenovo is 8 byte at 0x27b5a7c6240.
Run Code Online (Sandbox Code Playgroud)

tbx*_*are 5

向量使用多少字节?

向量在两个地方使用内存:1. 在向量对象本身内,2. 在存储向量元素的堆上。

编译器实现者在如何分配内存方面有很大的自由度。然而,通常情况下,矢量对象本身包含大小不变的部分。这是我在微软的实现中发现的:

  1. 指向堆上数据开头的指针,即第一个数据元素。

  2. 指向数据末尾的指针,即超出最终数据元素的一个元素。使用该指针,capacity()计算为end - first

  3. 标记使用的最后一个元素的指针,即指向使用的最后一个数据元素之后的元素的指针。使用此指针,size()计算为last - first

数据元素数组存储在堆上,可能包含其他实现特定信息(或不包含)。对于存储在堆上的数组,堆上可能会存储一块信息以及 C++ 运行时用来辅助操作符的数组delete[]

对于给定的向量v,假设除了数据元素数组之外没有任何内容存储在堆上,则使用的字节数将为:

sizeof(v) + (v.data() == nullptr ? 0 : v.capacity() * sizeof(*v.data()))
Run Code Online (Sandbox Code Playgroud)

原始问题中的向量是一个指针向量,具体来说,是指向 的指针const charinitializer_list该向量由6初始化string literals。字符串文字存储在静态内存中,而指向它们的指针作为向量数据存储在堆上。据推测,容量分配为 6,但我相信细节是特定于实现的。每个元素的大小是数据指针的大小,通常是sizeof(std::size_t).

这是一个计算所用字节总数的简短程序。希望原始发布者能够在他的系统上运行它,并告诉我们他得到了什么。

#include <cstddef>
#include <iostream>
#include <vector>
int main()
{
    std::vector<const char*> v = { "Microsoft", "Apple", "DELL", "Accer", "Lenovo", "hp" };
    std::cout << std::boolalpha
        << "sizeof(v)           : " << sizeof(v)
        << "\nv.size()            : " << v.size()
        << "\nv.capactity()       : " << v.capacity()
        << "\nv.data() == nullptr : " << (v.data() == nullptr)
        << "\nv.data()            : " << v.data()
        << "\nsizeof(*v.data())   : " << sizeof(*v.data())
        << "\nsizeof(std::size_t) : " << sizeof(std::size_t)
        << "\nTotal bytes used    : " << sizeof(v) + (v.data() == nullptr ? 0 : v.capacity() * sizeof(*v.data()))
        << "\n\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我在 MSVC 上运行,目标为 x64,所以我的指针每个都是 8 个字节。显然,矢量对象中存储了第四个项目,因为它是sizeof(v)在 32 上出现的,而不是 24 上。

sizeof(v)           : 32
v.size()            : 6
v.capactity()       : 6
v.data() == nullptr : false
v.data()            : 000002952A005030
sizeof(*v.data())   : 8
sizeof(std::size_t) : 8
Total bytes used    : 80
Run Code Online (Sandbox Code Playgroud)

在阅读微软 header 的源代码时<vector>,我能够找到上面提到的三个指针。_Mypair它们存储在名为的对象中_Mypair._Myval2。然而,我找不到 的定义_Mypair._Myval1,它大概是第四项。

当我以 x86 为目标重新编译时,大小减少了一半。这是有道理的,因为std::size_t用于指针的大小已减少到 4 个字节。

sizeof(v)           : 16
v.size()            : 6
v.capactity()       : 6
v.data() == nullptr : false
v.data()            : 00AEC640
sizeof(*v.data())   : 4
sizeof(std::size_t) : 4
Total bytes used    : 40
Run Code Online (Sandbox Code Playgroud)