• vs2019测试sizeof(string)的长度是28


    在csdn回答别人的问题时,偶然间接触到sizeof求sting的内存容量大小的问题,经过测试,结果有些意外,引发自己的深度思考,探索一番做整理。

    0:相关知识点

    为了分析sizeof(string)的大小,涉及到一些知识点:

    ====》sizeof()是静态运算符,关注的是参数类型,编译时决定了。

    ====》类的长度实际是类中非静态成员变量长度,无成员变量是1,有虚函数要维持虚函数表(一个指针大小),有基类时要算基类的成员吧。

    ====》类模板(通用的类)和模板类(实例化的类)的概念

    ====》可以用using对复杂的结构重新命名。

    ====》string的内存分配,实际上还是类中定义一个指针,真正赋值的时候去new具体的大小。

    ====》typename的新用法:用在模板定义中,把相关名称识别为类型。

    1. 问题描述(单纯记录引发我思考的起点):

    有新手同学在使用string及数组的时候,有误用,引发我的思考:

    //他的本意应该是想定义时确定一个数组的大小,故这样写了代码
    string s;
    char c[strlen(s.c_str())]={0}; //都是不对的代码
    int a[strlen(s.c_str())]={0};
    
    • 1
    • 2
    • 3
    • 4

    我能明确看出他的不对,因此我期望用demo去给他验证,数组下标是0,这里就涉及字符串string的一个长度问题,我抛出:

    //这是在vs 2019上运行的结果:
    int main()
    {
    	string s;
        //这里我的本意是让他理解及去梳理strlen(),length(),以及sizeof()这几个求长度函数的差异,却让自己深思一下
    	cout << strlen(s.c_str()) << endl;    //0
    	cout << s.length() << endl;           //0
    	cout << sizeof(s) << endl;            //28
    	cout << sizeof(string) << endl;       //28
    	return 0;
    }
    //探索后,发现在linux上运行的结果
    #include 
    #include 
    #include 
    using namespace std;
    int main()
    {
    	string s;
    	cout << strlen(s.c_str()) << endl;    //0
    	cout << s.length() << endl;           //0
    	cout << sizeof(s) << endl;            //32
    	cout << sizeof(string) << endl;       //32
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    检测测试发现:

    VS2019上sizeof(string)的长度是28

    linux上sizeof(string)的长度是32

    VS2022上sizeof(string)的长度是40

    2. 为什么sizeof(string)的长度是28,以及32,40

    第一眼懵逼,问了一把身边同事,他随口回答是类似array的预分配内存

    ===>emmmm,有点涉及,但是依然不对,这是string的其他知识点

    结合百度,明确以下信息:

    ====》用sizeof求string的结果,在不同的系统中结果是不同的。

    ====》用sizeof求string的大小,与string是否初始化也是无关的。

    ====》sizeof是静态运算符,在编译的时候获取到响应结果,而string对象的申请,一般都是在运行时动态分配。

    反思到,sizeof所求,其实是类所占用的大小,可以跟踪代码进行探索。

    3:跟踪一下string类的大小

    这里我在vs2019上试图跟踪了一下string类。 其他的类似吧~

    //string实际是 类模板 传入char
    using string  = basic_string, allocator>;
    
    //第一步:
    //这里实际是关注basic_string 中传入char时类所占内存的大小。
    //实际测试:
    cout << sizeof(basic_string111, allocator>) << endl;   //28
    //简化basic_string 相关的类中成员,最终类简化后占用内存的成员是:
    template , class _Alloc = allocator<_Elem>>
    class basic_string111 { // null-terminated transparent array of elements
    private:
    	using _Alty = _Rebind_alloc_t<_Alloc, _Elem>;
    	using _Alty_traits = allocator_traits<_Alty>;
    	using _Scary_val = _String_val, _Simple_types<_Elem>,
    		_String_iter_types<_Elem, typename _Alty_traits::size_type, typename _Alty_traits::difference_type,
    		typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Elem&, const _Elem&>>>;
    private:
    	_Compressed_pair<_Alty, _Scary_val> _Mypair;  //这是实际占用的
    };
    
    //第二步:
    //这里就需要研究成员变量的的大小了:    _Compressed_pair<_Alty, _Scary_val> _Mypair;
    //实际测试:
    cout << sizeof(_Alty) << endl;        //1
    cout << sizeof(_Scary_val) << endl;   //28
    cout << sizeof(_Compressed_pair<_Alty, _Scary_val>) << endl;     //28
    
    //第三步
    //接下来需要研究成员大小:    _Compressed_pair<_Alty, _Scary_val>大小为什么是28
    //首先获取到 _Compressed_pair 实际也是一个类模板    中间有个成员变量 实际是模板第二个参数
    template  && !is_final_v<_Ty1>>
    class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty first
    public:
        _Ty2 _Myval2;
        using _Mybase = _Ty1; // for visualization
    };
    
    //====>所以 _Compressed_pair 的大小,实际上可以确定是第二个模板参数 也就是_Scary_val 的大小。
    //====>_Scary_val  实际又是 类模板 
    using _Scary_val = _String_val, _Simple_types<_Elem>,
    		_String_iter_types<_Elem, typename _Alty_traits::size_type, typename _Alty_traits::difference_type,
    		typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Elem&, const _Elem&>>>;
    // ====》也就是确定 这个类模板 对应传参实际大小   
    template 
    class _String_val111 : public _Container_base {
    public:
    	// length of internal buffer, [1, 16]:
    	static constexpr size_type _BUF_SIZE = 16 / sizeof(char) < 1 ? 1 : 16 / sizeof(char);  
    
    	union _Bxty { // storage for small buffer or pointer to larger one
    		_Bxty() noexcept {} // user-provided, for fancy pointers
    
    		~_Bxty() noexcept {} // user-provided, for fancy pointers
    
    		value_type _Buf[_BUF_SIZE];
    		pointer _Ptr;
    		char _Alias[_BUF_SIZE]; // TRANSITION, ABI: _Alias is preserved for binary compatibility (especially /clr)
    	} _Bx;
    
    	typename size_t _Mysize; 				// 4个字节 typedef unsigned int     size_t;
    	typename _Val_types::size_type _Myres;  // 4个字节 实际是模板参数传参对应的size_type 类型  实际还是size_t
    };
    
    //第四步:实际上就是分析_String_val111 所占大小
    //为了确定_Val_types::size_type 的类型及长度    跟踪一下模板参数:conditional_t 
    _String_val111, _Simple_types,
    		_String_iter_types>>
    //可以确定他实际是  _Simple_types中对应的size_type    
     template 
    struct _Simple_types1 { 
    	using value_type = _Value_type;
    	using size_type = size_t;   //===》实际是这个  也是unsigned int
    	using difference_type = ptrdiff_t;
    	using pointer = value_type*;
    	using const_pointer = const value_type*;
    };
    //分析后可以确定   
    //_String_val111 类中,成员变量的长度是 union (16) + size_t(4) +_Val_types::size_type(4)  +基类成员中有一个指针(4) = 28
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    最终 跟踪vs2019中string相关类的定义,可以确定sizeof(string)所求长度就是类中成员变量的总长度 28

    4:总结涉及到的知识点。

    为了分析sizeof(string)的大小,涉及到一些知识点:

    ====》sizeof()是静态运算符,关注的是参数类型,编译时决定了。

    ====》类的长度实际是类中非静态成员变量长度,无成员变量是1,有虚函数要维持虚函数表(一个指针大小),有基类时要算基类的成员吧。

    ====》类模板(通用的类)和模板类(实例化的类)的概念

    ====》可以用using对复杂的结构重新命名。

    ====》string的内存分配,实际上还是类中定义一个指针,真正赋值的时候去new具体的大小。

    ====》typename的新用法:用在模板定义中,把相关名称识别为类型。

  • 相关阅读:
    NodeJs实战-待办列表(4)-解决待办事项中文乱码问题
    利用python中if函数判断三角形的形状
    DA2--获取网站用户数据集的大小
    剑指offer专项突击版第26天
    仿真与烧录程序有哪几种方式?(包含常用工具与使用方式)
    CentOS 7 安装LibreOffice 7.4.0 过程
    非常有用的JavaScript高阶面试技巧!
    Add the installation prefix of “Qt5“ to CMAKE_PREFIX_PATH or set “Qt5_DIR“解决
    el-table 边框颜色修改 简单有效!
    【跨境电商平台】Magento VS Shopify,选谁进行独立站建站?
  • 原文地址:https://blog.csdn.net/yun6853992/article/details/126208015