欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-06 19:05:22
...

【问题-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;
}

<输出结果>:

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

<分析> :

       类的大小不会随着成员内容器元素个数的增加而增大,容器中的元素个数增加不会增加容器变量的大小,原因是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也可能分配失败。

相关标签: 程序员应知应会