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

简介: 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};

我能明确看出他的不对,因此我期望用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 <stdio.h>
#include <iostream>
#include <string.h>
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;
}

检测测试发现:

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<char, char_traits<char>, allocator<char>>;
//第一步:
//这里实际是关注basic_string 中传入char时类所占内存的大小。
//实际测试:
cout << sizeof(basic_string111<char, char_traits<char>, allocator<char>>) << endl;   //28
//简化basic_string 相关的类中成员,最终类简化后占用内存的成员是:
template <class _Elem, class _Traits = char_traits<_Elem>, 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<conditional_t<_Is_simple_alloc_v<_Alty>, _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 <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !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<conditional_t<_Is_simple_alloc_v<_Alty>, _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 _Val_types>
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<conditional_t<_Is_simple_alloc_v<_Alty>, _Simple_types<char>,
    _String_iter_types<char, typename _Alty_traits::size_type, typename _Alty_traits::difference_type, typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, char&, const char&>>>
//可以确定他实际是  _Simple_types<char>中对应的size_type    
 template <class _Value_type>
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

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

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

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

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

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

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

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

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

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

目录
相关文章
|
2天前
|
Linux 编译器 数据安全/隐私保护
Windows10 使用MSYS2和VS2019编译FFmpeg源代码-测试通过
FFmpeg作为一个流媒体的整体解决方案,在很多项目中都使用了它,如果我们也需要使用FFmpeg进行开发,很多时候我们需要将源码编译成动态库或者静态库,然后将库放入到我们的项目中,这样我们就能在我们的项目中使用FFmpeg提供的接口进行开发。关于FFmpeg的介绍这里就不过多说明。
84 0
|
2天前
|
Linux C++
(C++)VS下sizeof(string(““))与linux-g++下sizeof(string(““))大小区别及原因剖析
(C++)VS下sizeof(string(““))与linux-g++下sizeof(string(““))大小区别及原因剖析
37 0
(C++)VS下sizeof(string(““))与linux-g++下sizeof(string(““))大小区别及原因剖析
|
缓存 NoSQL API
分布式服务器框架之Servers.Common中使用CSRedis测试操作Redis中的string、hash_table、list、set、zset
在Servers.Common类库总创建了一个TestRedis.cs文件,我是在Servers.GameServer中去初始化的。主要是测试了Redis中常用的数据类型和常用的API,有一些不常用的可能没有写。需要详细了解API的话可以安装上CSRedis之后F12追进去查看,上面有详细的API说明。
分布式服务器框架之Servers.Common中使用CSRedis测试操作Redis中的string、hash_table、list、set、zset
|
存储 算法 安全
初阶C++——STL——string类、vector类和list类(使用方法+模拟实现+测试+思路分析)
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本--所有STL实现版本的始祖。
319 0
初阶C++——STL——string类、vector类和list类(使用方法+模拟实现+测试+思路分析)
微软在线测试之lucky string,有关斐波那契的题目都在此了
解决方案: int _tmain(int argc,_TCHAR* argv[]) { size_t fib[] = {1,2,3,5,8,13,21,34}; string str,tempstr; cin >> str; tempstr = str; auto it = unique(tempstr.
1158 0
|
测试技术 C#
C#转换为String的效率测试
  今天早上突然想起转换string的效率问题,于是就在百度和google查了个遍,但是似乎众说纷纭,只好自己亲自东西测试下了。   先来说说常用的方式吧:(string),Convert.ToString(),ToString().
674 0
Dictionary<string,object>性能之测试
添加二百万记录时间 16秒 用键查询值的平均时间,0MS 内存使用 150M 代码: /**//* * Created by 邹健 * Date: 2008-2-14 * Time: 10:21 *  *  */namespace test{    using System;    using System.
686 0
|
2天前
|
安全 Java 编译器
Java中String、StringBuilder和StringBuffer的区别
Java中String、StringBuilder和StringBuffer的区别
10 1
|
2天前
|
存储 缓存 安全
【 Java中String源码分析(JVM视角你不来看看?】
【 Java中String源码分析(JVM视角你不来看看?】
14 0