程序员应了解的那些事(9) STL vector:sizeof(vector)分析 + sizeof小结

【问题-1】int的大小是4,定义vector<int> vec,vec中有一个元素,sizeof(vec)=20,如果有1000个元素,则sizeof(vec)是多少?

<写代码测试一下>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int> vec;
    for(int i=0;i<100;i++)
    {
    vec.push_back(i);
    cout<<sizeof(vec)<<endl; 
    cout<<vec.size()<<endl;
    } 
}
输出结果:
20
1
……
20
100

 由此可以看出:sizeof(vec)只取决于vector里面存放的数据类型,与元素个数无关。该值应该是与编译器相关的。

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    cout<<"sizeof(vector<char>) = "<<sizeof(vector<char>)<<endl;
    cout<<"sizeof(vector<int>) = "<<sizeof(vector<int>)<<endl;
    cout<<"sizeof(vector<short>) = "<<sizeof(vector<short>)<<endl;
    cout<<"sizeof(vector<double>) = "<<sizeof(vector<double>)<<endl;
    cout<<"sizeof(vector<long>) = "<<sizeof(vector<long>)<<endl;
    cout<<"sizeof(vector<float>) = "<<sizeof(vector<float>)<<endl;
    cout<<"sizeof(vector<bool>) = "<<sizeof(vector<bool>)<<endl;
    cout<<"sizeof(vector<string>) = "<<sizeof(vector<string>)<<endl;
}
输出结果:
sizeof(vector<char>)   = 20
sizeof(vector<int>)    = 20
sizeof(vector<short>)  = 20
sizeof(vector<double>) = 20
sizeof(vector<long>)   = 20
sizeof(vector<float>)  = 20
sizeof(vector<bool>)   = 28
sizeof(vector<string>) = 20

大小为什么有的是20,有的是28?与容器类型有关么?
解释:
vector元素应该是从堆上分配内存,栈上只有一部分用于管理的指针,所以 sizeof(vector)大小与元素个数无关;
sizeof(vector)取决于vector类的具体实现,STL是个完全开放的东西,谁都可以来实现vector类。

通过查看STL源码可以看到vector有四个成员变量 
_A   allocator; 
iterator   _First,   _Last,   _End; 
每个指针是4个字节,因此16字节。20字节的是不是添加了什么指针呢?

【问题-2】C++类中包含stl容器时,使用sizeof求类对象大小。

<测试类>
class KFoo
{
public:
    KFoo(void)
    {
        m_nValue = 0;
        m_cEnd ='0';
        m_listValue.clear();
        m_vectorValue.clear();
        m_mapValue.clear();
    };
    ~KFoo(void){};
public:
    inline void SetValue(const int nValue)
    {
        m_nValue = nValue;
    }
public:
    int             m_nValue;
    list<int>       m_listValue;        //24
    vector<int>     m_vectorValue;      //20
    map<int, int>   m_mapValue;         //28
    char            m_cEnd;
};
<测试类大小的函数>
#include "Foo.h"
#include <Windows.h>
#include <stdio.h>
int main(int argc, _TCHAR* argv[])
{
    KFoo foo;
    foo.SetValue(0);
    foo.m_cEnd = 'a';

    printf("begin: Class object foo size = %d\n\n", sizeof(foo));

    printf("begin: list size = %d\n", sizeof(foo.m_listValue));
    for(int nIndex = 0; nIndex < 1024; ++nIndex)
    {
        foo.m_listValue.push_back(nIndex);
    }
    printf("begin: list size = %d\n\n", sizeof(foo.m_listValue));

    printf("begin: vector size = %d\n", sizeof(foo.m_vectorValue));
    foo.m_vectorValue.resize(2048);
    for(int nIndex = 0; nIndex < 2048; ++nIndex)
    {
        foo.m_vectorValue.push_back(nIndex);
    }
    printf("begin: vector size = %d\n\n", sizeof(foo.m_vectorValue));

    printf("begin: vector size = %d\n", sizeof(foo.m_mapValue));
    for(int nIndex = 0; nIndex < 4096; ++nIndex)
    {
        foo.m_mapValue.insert(make_pair<int, int>(nIndex, nIndex));
    }
    printf("begin: vector size = %d\n\n", sizeof(foo.m_mapValue));

    printf("end: Class object foo size = %d\n\n", sizeof(foo));
    system("pause");
    return 0;
}

<输出结果>:

<分析> :

       类的大小不会随着成员内容器元素个数的增加而增大,容器中的元素个数增加不会增加容器变量的大小,原因是sizeof是无法求出容器所占内存的,这些容器申请的大部分空间都是在堆上,栈上只有一部分用于管理的指针。测试得出sizeof(list)=24,sizeof(vector)=20,sizof(map)=28,这个数值和具体的编译器实现有关。

【拓展-1/sizeof小结】    ※sizeof 计算的是在栈中分配的内存大小!!!
         ※sizeof 计算的是在栈中分配的内存大小!!!
(1) sizeof 不计算 static 变量占的内存!  //sizeof只计算栈中分配的大小,静态变量存放在全局数据区,不加入运算!!

(2) 指针的大小一定是 4 个字节,而不管是什么类型的指针;
(3) char 型占 1 个字节,int 占 4 个字节,short int 占 2 个字节,long int 占 4 个字节,float 占 4 字节,double 占 8 字节,string占 4 字节;一个空类占 1 个字节,单一继承的空类占 1 个字节,虚继承涉及到虚指针所以占 4 个字节;
(4) 数组的长度:
         若指定了数组长度,则不看元素个数,总字节数 = 数组长度 * sizeof(元素类型);
         若没有指定长度,则按实际元素个数类确定;
         PS:若是字符数组,则应考虑末尾的空字符。
(5) 结构体对象的长度
       在默认情况下,为方便对结构体内元素的访问和管理,当结构体内元素长度小于处理器位数的时候,便以结构体内最长的数据元素的长度为对齐单位,即为其整数倍。若结构体内元素长度大于处理器位数则以处理器位数为单位对齐。
(6) unsigned 影响的只是最高位的意义,数据长度不会改变,所以 sizeof(unsigned int)= 4;
(7) 自定义类型的 sizeof 取值等于它的类型原型取 sizeof
(8) 对函数使用 sizeof,在编译阶段会被函数的返回值的类型代替
(9) sizeof 后如果是类型名则必须加括号,如果是变量名可以不加括号,这是因为 sizeof 是运算符;
(10)sizeof之继承

          ①基类的sizeof结果只与基类有关;
          ②因存在继承关系,所以派生类的sizeof结果需要加上基类的sizeof结果;
          ③当基类和派生类均有虚函数时,只计算一次sizeof(虚表指针)。

【拓展-2/sizeof 与 strlen 的区别】
(1)sizeof 的返回值类型为 size_t(unsigned int);
(2)sizeof 是运算符,而 strlen 是函数;
(3)sizeof 可以用类型做参数,其参数可以是任意类型或者是变量、函数,而 strlen 只能用char*做参数,且必须是以’\0’ 结尾;
(4)数组作 sizeof 的参数时不会退化为指针,而传递给 strlen 是就退化为指针;
(5)sizeof 是编译时的常量,而 strlen 要到运行时才会计算出来,且是字符串中字符的个数而不是内存大小。

【问题-3】sizeof为什么不能计算被动态分配的数组?
  答:sizeof()只是符号表,是编译的时候确定大小的。动态分配是运行过程中得到大小的。甚至new也可能分配失败。

  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值