sizeof(Vector<>)大小问题

先来看一个例子:

struct record{
     string name;
     int age;
     vector<int> grades;
};

则sizeof(record)大小为多少?

答案是:20(G++编译器下)

了解string,int的朋友很熟悉,string和int在G++下都是4字节,这样看来 grades的大小应为12字节。

给grades中放入三个整型值,100,110,120,sizeof(grades),竟然还是12!

由此说来,sizeof(vector<type>)的大小,跟容器里面存放多少数据无关,它是在编译期确定的一个值,仅跟具体的编译器有关

用一段程序测试一下:

老编译器测试:

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;

结果如下:

可以看出除了bool类型外,其他类型的容器大小均为12字节,经检测VC6.0下这个值是16,在VS2003以后该值是20.

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

所以,要想查看一个容器v的大小:

可以使用sizeof(v) + sizeof(T) * v.capacity();//T是v中元素类型

#########################

新编译器测试:
#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)取决于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、如果一个class中包含一个vector容器,那么sizeof(class_name)的值应该怎么算?

#include <iostream>
#include <vector>

using namespace std;

class CDocument{
public:
    int i;
    vector<long long> vec;

};


int main(){
    CDocument mydoc;
    cout << sizeof(mydoc.vec) << endl; //12
    cout << sizeof(CDocument) << endl; //16,即12+4
    for(int i = 1; i <= 5; i++)
        mydoc.vec.push_back(i);
    cout << sizeof(CDocument) << endl; //16
    cout << sizeof(mydoc) << endl;     //16
}

        题目中所描述的是C++类与类关系的一种:叫做Composition(复合),所以在计算sizeof(class_name)的值时,只需要将复合的类展开,展开以后再按照传统的计算单个类的sizeof(class_name)去进行计算就可以了。

图示如下:


2、复合关系的构造和析构顺序

        关于复合关系,我们还需要明白的是,对象的构造和析构的过程中两个类的构造函数和析构函数的先后顺序是什么样子的,其实就和继承时构造和析构的顺序类似,见图:


注意图中红字的部分是编译器来帮我们做的。

3、复合关系的内存回收

        所以当我们在一个class A中放置了一个容器(假设vector<int> vec)时,当我们使用A创建了一个对象obj,并且有一个指针ptr指向了obj,此时delete ptr,就会调用A的析构函数,而此时编译器也帮助我们去调用容器的析构函数,来完成整个内存的回收,这个过程并不需要我们人为的使用vec.clear()来回收vector的内存。

【拓展-1/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也可能分配失败。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值