接上文,我们知道在C++中sizeof计算map或者vector的大小的时候,无论容器里面有多少元素,返回的都是固定值,这个固定值就是C++中map或者vector这个数据结构本身所占用的空间。
对于vector来说,上文实测占用24字节,分成3个8字节的ptr,分别表示vector中首个元素的地址,下一个待插入的地址和后续扩展地址(当下一个地址达到后续扩展时,容器会自动再申请一段空间)。
对于map来说,上文实测占用48字节,但是具体着48字节表示什么,我们还灭有查到。本文再次进行分析:
#include <iostream>
#include <unistd.h>
#include <map>
#include <memory.h>
using namespace std;
int main(int argc, char** argv)
{
std::map<std::string,int> smap;
std::map<int,int> imap;
unsigned long addr1[6]={0},addr2[6]={0};
printf("smap addr= %p, sizeof(smap)=%d\n",&smap,sizeof(smap));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&smap))+i));
}
printf("begin to insert content:\n");
smap.insert(std::make_pair("123",1));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&smap))+i));
}
printf("\n-------------\n");
memcpy(addr1,&smap,48);
smap.insert(std::make_pair("234",2));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&smap))+i));
}
printf("\n-------------\n");
memcpy(addr2,&smap,48);
for(unsigned long i= addr1[4];i<addr2[4];i++)
{
printf("%02X ",*(unsigned char*)i);
}
printf("\n*************\n");
printf("imap addr= %p, sizeof(imap)=%d\n",&imap, sizeof(imap));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&imap))+i));
}
return 0;
}
从一些资料分析的结果显示,std::map用的红黑树进行组织,这48个字节的后32个字节表示当前时刻map中的最后一个节点对应的红黑树结构,包括父节点地址,左节点地址,右节点地址,以及当前map中的元素数量。(前16个字节在map插入、删除过程中不变)
随着节点的插入与删除,红黑树的各节点会不断变化,在这个例子里,红黑树的一个节点大小为80字节(这个可能跟map的类型有关).这个80个字节里面包含了这个节点的父节点所在位置,这个节点的key的长度和内容,value的内容等信息。具体的,我还没有彻底看明白。比如下面*****之上打印的内容中,51 00 00 之前的01 00 00 00 00 00 00 00就是value,再往前的31 32 33 00 00 00 00 00 00表示key的内容,再往前的03 00 00 00 00 00 00 00 00表示key的长度;再往前8个字节表示key的所在位置,也就是0x5576EAAE32F0指向31 32 33所在位置,用于定位key。再往前的8个字节表示如果插入下一个节点,应该插入的位置。后面其他的,暂时不分析了。够用就行了。
#include <iostream>
#include <unistd.h>
#include <map>
#include <memory.h>
using namespace std;
int main(int argc, char** argv)
{
std::map<std::string,int> smap;
std::map<int,int> imap;
unsigned long addr1[6]={0},addr2[6]={0};
printf("smap addr= %p, sizeof(smap)=%d\n",&smap,sizeof(smap));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&smap))+i));
}
printf("begin to insert content:\n");
smap.insert(std::make_pair("123",1));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&smap))+i));
}
printf("\n-------------\n");
memcpy(addr1,&smap,48);
smap.insert(std::make_pair("234",2));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&smap))+i));
}
printf("\n-------------\n");
memcpy(addr2,&smap,48);
printf("addr1[4] = %p, addr2[4]=%p\n",addr1[4],addr2[4]);
for(unsigned long i= addr1[4];i<addr2[4];i++)
{
printf("%02X ",*(unsigned char*)i);
}
printf("\n*************\n");
smap.insert(std::make_pair("45678",4));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&smap))+i));
}
printf("\n-------------\n");
memcpy(addr1,&smap,48);
for(unsigned long i= addr2[4];i<addr1[4];i++)
{
printf("%02X ",*(unsigned char*)i);
}
printf("\n*************\n");
printf("imap addr= %p, sizeof(imap)=%d\n",&imap, sizeof(imap));
for(int i =0; i<48; i++)
{
printf("%02X ",*(((unsigned char *)(&imap))+i));
}
return 0;
}