std::string在 Windows MSVC和Linux Gcc 中capacity容量扩容策略的分析和对比

1、capacity()作用

       在std::string中,capacity()为当前string占用内存字符的长度,表示当前string的容量,可以理解为一个预分配制度,如果当前的string不断进行扩展操作,则不需要每次都进行内存上的分配,提高程序的运行效率。所以capacity的值会大于等于size,而不是代表当前string的实际大小。

2、Gcc分配策略

        查看Gcc关于string的capacity的代码,大致如下:

分配通过_M_mutate实现,_M_mutate再调用_M_create,调用实际的分配策略。

_M_mutate():

_M_create():

_M_max_size()如下:

       可以看到,当所要扩容后的capacity如果大于_M_max_size,会抛出异常。这里不展开关注,只需要关注在正常可以扩容的情况下的capacity的变化。如果所要扩容后的capacity大于老的capacity,则进行二倍的的扩展。这就是Gcc的分配策略。

3、MSVC分配策略

MSVC通过_Calculate_growth()完成capacity的扩容处理。代码如下:

        _ALLOC_MASK,为15,这个值是在编译期确定的值

        每次capacity分配都会将需要将string的请求长度_Requested与_Alloc_Mask进行或运算,得到一个_Requested加上一个<=15的值_Masked如果该值大于_Max,则最大分配为_Max,不会像Gcc先抛出异常。

        然后将该值与旧值大小的1/2增长进行比较,取两者的较大的值为新的capacity。

4、代码验证

        测试思路,先定义一个空的string,查看初始的capacity值,然后做10次扩容测试,查看每次扩容后的capacity情况。

测试代码如下:

#include <iostream>
#include <string>
using namespace std;
int main()
{
    std::string str;
    std::cout<<"origin capacity: "<<str.capacity() << " size: "<<str.size()<<std::endl;
    for (int i = 0; i < 10; i++)
    {
        auto cap = str.capacity();
        while(str.size() <= cap)
        {
            str.append("1");
        }
        std::cout<<"capacity: "<<str.capacity() << " size: "<<str.size()<<std::endl;
    }
    return 0;
}

4.1 Windows下capacity变化情况

        可以看出,一个空的string的capacity初始值系统分配为15,然后再扩容后,后面每次capacity的大小为size/2 + size

4.2 Linux下capacity变化情况

Linux下为一个空的string分配的初始capacity也是15,后面每次进行扩容,都是当前(size/2)*2。

5、横向比对Gcc和MSVC的分配策略

        MSVC的扩容要小于Gcc下的扩容大小,这决定了在Linux下string进行不断进行增大时,效率要优于Windows,分配的频率会小于Windows。但是Linux下分配会占用的内存大于Windwos环境,这也可以理解,因为Linux本身运行的程序多为企业级多并发的大程序,利用Linux高资源的特点,可以用空间换时间,获得更快的运行效率。而Windows下运行的多为单机程序,运行的程序不像Linux环境下那么庞大,也不需要极致的空间置换时间,且Wndows的系统资源比较有限,这样可以在保证程序高效运行的情况下,兼顾系统资源在多程序之间的合理分配。

6、capacity扩容后的元素内存地址的变化

        我们vector内部的内存结构也是一块连续的内存,当容量进行扩展后,需要重新分配内存,然后进行内容的迁移,string是不是也是如此,进行代码验证。

        每次都监视首个元素的地址,当元素插入超过15时,看是否发生首个元素地址的变化。

        测试代码如下:

        

int main()
{
    string str; 
	for (int index = 0; index < 20; ++index)
	{
		str.push_back('1');
		std::cout << "size: " << str.size() << " capacity: " << str.capacity() << " str address: " << &str << " data address: " << (const void*)(&str[0]) << endl; 
    }
    return 0;
}

测试结果如下:

可以看到扩容后首个元素的内存地址也是发生了变化,和vector一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/271332.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

iconify图标集离线使用方案简介

1.需求描述 前端项目&#xff0c;技术栈使用Vue3Element Plus&#xff0c;参考了ruoyi-vue-pro项目与vue-element-plus-admin项目&#xff0c;封装了一个Icon组件&#xff0c;图标使用的是iconify,项目部署在内网环境&#xff0c;不能连接互联网&#xff0c;需要部署一套iconi…

MAC鼠标中键的使用

MAC鼠标没有鼠标中键&#xff0c;于是在一些场景中用起来非常麻烦&#xff0c;这里介绍几种键盘快捷键鼠标左键实现中键功能的例子&#xff1a; 1&#xff09;在sublime text 或者pycharm等一些文本编辑器或IDE中实现中键修改一列数据中特定位置的值 FNOPT左键另外还有C4D&…

生存分析序章1——解析生存分析:探寻时间与事件的奥秘

写在开头 生存分析&#xff0c;作为统计学和生物学交汇的领域&#xff0c;旨在探究时间与事件之间的奥秘。这一领域的深入研究不仅在医学和生物学领域有着广泛的应用&#xff0c;同时在数据分析和数据挖掘中也发挥着关键作用。 1 基本概念 1.1 什么是生存分析 生存分析&…

STM32独立看门狗和窗口看门狗的区别

独立看门狗&#xff1a; 本质上是一个定时器&#xff0c;这个定时器有一个输出端&#xff0c;可以输出复位信号。 该定时器是一个 12 位的递减计数器&#xff0c;当计数器的值减到 0 的时候&#xff0c;就会产生一个复位信号。如果在计数没减到 0 之前&#xff0c;重置计数器的…

如何使用 NestJS 集成 Passort 和 JWT Token 实现 HTTP 接口的权限管理

&#x1f4a1; 如果你不希望其他人可以随意进出你的房子&#xff0c;那么你需要给你的房子上个锁。 前言 开发一个接口很容易&#xff0c;开发一个具有安全性的接口却不容易。成熟的后端服务项目最注重的一点就是如何保护系统的数据安全&#xff0c;不能让用户无脑的访问操作所…

大数据Doris(四十一):物化视图简单介绍

文章目录 物化视图简单介绍 一、适用场景

利用html2Canvas将表格下载为html

给到我的需求是点击按钮时请求后端接口&#xff0c;根据后端返回的数据&#xff0c;生成表格,并将表格的内容直接下载为html,如下图。 平常做的下载都是后端返回二进制流&#xff0c;这次前端做下载那就必须把页面先画出来&#xff0c;因为下载下来的表格在页面上是不显示的&a…

Keepalived 高可用详解

Keepalived 详解 1、Keepalived介绍 ​ Keepalived是一个基于VRRP协议来实现LVS服务高可用方案&#xff0c;可以利用其来避免单点故障。一个LVS服务会使用2台服务器运行Keepalived&#xff0c;一台为主服务器MASTER&#xff0c;另一台为备份服务器BACKUP&#xff0c;但是对外表…

12月25日作业

串口发送控制命令&#xff0c;实现一些外设LED 风扇 uart4.c #include "uart4.h"void uart4_config() {//1.使能GPIOB\GPIOG\UART4外设时钟RCC->MP_AHB4ENSETR | (0x1 << 1);RCC->MP_AHB4ENSETR | (0x1 << 6);RCC->MP_APB1ENSETR | (0x1 <…

深入剖析LinkedList:揭秘底层原理

文章目录 一、 概述LinkedList1.1 LinkedList简介1.2 LinkedList的优点和缺点 二、 LinkedList数据结构分析2.1 Node节点结构体解析2.2 LinkedList实现了双向链表的原因2.3 LinkedList如何实现了链表的基本操作&#xff08;增删改查&#xff09;2.4 LinkedList的遍历方式 三、 …

静态HTTP的未来:探讨新技术趋势

在Web的世界里&#xff0c;静态HTTP一直是个不可或缺的角色。它就像一个尽职尽责的邮递员&#xff0c;确保数据安全、准确地送达目的地。但随着时代的发展&#xff0c;邮递员也需要跟上潮流&#xff0c;不断学习和进步。那么&#xff0c;静态HTTP的未来会是怎样的呢&#xff1f…

CMMI-项目总体计划模版

目录 1、总体目录结构 2、重点章节概要示例 2.1 第四章 项目管理 2.2 第六章 实施与交付计划 2.3 第七章 运维计划 1、总体目录结构 2、重点章节概要示例 2.1 第四章 项目管理 2.2 第六章 实施与交付计划 2.3 第七章运维计划

从流星雨启程:Python和Pygame下载与安装全过程

文章目录 一、前言二、下载安装过程1.官网下载安装包2.安装python过程第一步第二步第三步第四步第五步安装完成 3.简单测试Python3.1 检查 Python 版本号3.2 打开 Python 解释器3.3 输入你的第一个代码3.4 运行 Python 脚本 4.安装Pygame4.1 cmd命令安装Pygame4.2 pip升级4.3 安…

C++的面向对象学习(6):运算符的重载

文章目录 前言&#xff1a;什么是运算符重载&#xff1f;针对自定义的类与对象类型。一、加号的运算符重载1.引入背景2.所以运算符重载的作用&#xff1a;3.实现对象间的相加代码&#xff1a;号运算符重载①在类中实现加号运算符重载②设计全局函数实现加号运算符重载③改写函数…

基于QListWidget的多段曲线展示器

目录 1 开发背景 2 创建程序 3 更改main window函数 4 测试构造函数 5 文件打开函数 6 拖放的实现 1 开发背景 由于视图控件的拖放逻辑比较难&#xff0c;需要同时子类化视图和模型&#xff0c;那么对于小数据而言&#xff0c;不如使用便捷类。因此&#xff0c;决定对多…

JavaOOP篇----第十八篇

系列文章目录 文章目录 系列文章目录前言一、什么是成员内部类二、Static Nested Class 和 Inner Class的不同三、什么时候用assert四、Java有没有goto前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女…

探索音乐创作的新境界——PreSonus Studio One Pro 6

音乐是人类情感的表达方式之一&#xff0c;而音乐制作编曲软件则是让人们将创意转化为音乐作品的重要工具之一。在众多软件中&#xff0c;PreSonus Studio One Pro 6凭借其强大的功能和出色的用户体验&#xff0c;成为了许多音乐制作人的首选。 首先&#xff0c;PreSonus Stud…

App应用如何在应用市场获得更多下载量?

App的转化率至关重要&#xff0c;App如何获得更多用户&#xff0c;提高应用的下载量&#xff1f; 据 Apple 称&#xff0c;每周有 6.5亿访问者访问应用商店&#xff0c;77%的应用下载来自 iOS 应用商店的自然搜索。随着 Apple 默认关闭了IDFA&#xff0c;自然搜索比以往任何时…

git之UGit可视化工具使用

一、下载安装UGit 链接&#xff1a;https://pan.baidu.com/s/1KGJvWkFL91neI6vAxjGAag?pwdsyq1 提取码&#xff1a;syq1 二 、使用SSH进行远程仓库连接 1.生成SSH密钥 由于我们的本地 git仓库和 gitee仓库之间的传输是通过SSH加密的&#xff0c;所以我们需要配置SSH公钥。才…

结合教学经验谈计量经济学与Stata软件的学习

1.经济金融专业学生计量学习之痛 教学实践中&#xff0c;很多学生跟我抱怨计量经济学难学的问题&#xff0c;也有很多研0的同学感觉本科阶段没学好&#xff0c;或者跨专业考研的同学&#xff0c;在知道了计量经济学的重要性之后&#xff0c;对于经济金融领域的“无计量、不科研…