C++的IO流与STL的空间配置器详解

 更新时间:2026年05月20日 09:41:01   作者:青瓦梦滋  
这篇文章给大家介绍C++的IO流与STL的空间配置器的相关知识,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

C++的IO流

在C++中,输入数据和输出数据用的是 cin >> cout << ,cin的>>表示设备的数据流入对应变量,cout的<<表示对应变量数据流出到设备,因此这种输入输出的过程被形象的比喻为“流”。

istream/ostream

cin是标准库中定义的istream类型的全局对象;cout是标准库中定义的ostream类型的全局对象

iostream继承了istream和ostream,因此用iostream实例化的对象可以输入+输出

它们调用的>>、<<本质上是调用的operator>>()operator<<()方法

int x;
cin >> x;
cin.operator>>(x);//与上面等价
cout << x;
cout.operator<<(x);//与上面等价

cout和cin不需要向C语言的scanf和printf一样手动指定类型,是因为cin的>>,cout的<<对每个内置类型都做了重载

int x;
while(cin >> x)
{
    //
}

对于上面代码,可以保证有数据时一直循环,当输入 Ctrl + Z (EOF标志)时再跳出循环,这本质是得益于istream类重载的 operator bool 方法,允许流对象在布尔上下文中自动转换为bool值(istream的>>重载原本返回的是istream&类型)

ifstream/ofstream

 ifstream ofstream 是C++中用于文件IO流的两个类,前者仅可以读取,后者仅可以写入,若想读取+写入可以用 fstream 

//模式默认是out,即以输出模式打开
ofstream ofs("text.log"/*,ios::out*/);//fopen("text.log","w");
ofs << "eee";//向文件中写入
ofs.close();//关闭文件
//模式默认是in,即以输入模式打开
string str;
ifstream ifs("text.log"/*,ios::in*/);//fopen("text.log",r);
ifs >> str;//读取到str中
cout << str;

若不在构造函数中指定文件,也可以后续用 open() 方法

ofs.open("text.log"/*,ios::out*/);
ifs.open("text.log"/*,ios::in*/);

需要注意的是,ofstream的<<只会写入文本,例如ofs << 123,写入的也是1,2,3的ASCII码

而ofstream的 write() 方法可以写入二进制码,例如ofs.write(123),写入的是4字节二进制值
0x7B 0x00 0x00 0x00(小端序)

ifstream的>>也只会读取文本,若写入时是以二进制写入,读取也需要以二进制读取,可以用 read() 方法,但要用read读取就必须在打开文件时指定模式 ios::binary ,表示以二进制方式打开。

ifstream/ofstream的>>/<<的优点就是,在想以字符串格式写入数字型数据时,不需要先把数字转换成字符串(例如tostring())

info student("张三",20);
ofstream ofs("text.log");
ofs << student._name << endl;
ofs << student._age << endl;//不需要转成字符串再传入
ofs.close();
info s;
ifstream ifs("text.log");
ifs >> s._name;
ifs >> s._age;
cout << s._name << ' ' << s._age << endl;

ps: fstream继承自iostream,而iostream又继承了ifstream和ofstream,因此fstream实例化的对象可读可写

istringstream/ostringstream

istringstream/ostringstream类用于将整型数据转换为字符串(例如itoa(),tostring()等)或将字符串转换为对应数据类型,前者可以从字符串中读取数据(输入流),常用于字符串解析和类型转换,后者用于向字符串写入数据(输出流),常用于格式化拼接和类型转换

若要将不同类型的数据都转为字符串,就可以用 ostringstream 向字符串 写入数据

若要将字符串再分割为基本类型,就可以用 istringstream 

//序列化(转换为字符串)
info student("张三",20);
ostringstream ost;
ost << student._name << endl;
ost << student._age << endl;
//反序列化(从字符串转换为数据)
info st;
istringstream ist;
ist.str(ost.str());
ist >> st._name >> st._age;
cout << st._name << ' ' << st._age << '\n';

ps: stringstream继承自iostream,而iostream又继承了istringstream和ostringstream,因此stringstream是支持读写的双向流,可解析可拼接

该对象常用于网络字符串拼接与解析

空间配置器

STL的空间配置器简单来说是内存池,负责在容器申请内存时分出内存,这避免了频繁申请内存导致的效率开销问题。空间配置器本质也是以空间换时间的策略,因为池化技术的缺点就是不用时也会占用资源。空间配置器分为一级空间配置器二级空间配置器

一级空间配置器

一级空间配置器就是malloc和free的封装,并处理失败抛异常机制。

在malloc开辟失败时,会先检测使用者有无设置失败的处理函数(一个函数指针),如果有就执行,否则抛异常。默认情况下没有设置该失败的函数指针句柄,即跟operator new基本一样,失败抛异常

要申请超过128字节的内存时,才会使用一级空间配置器,若在128字节以内,会用二级空间配置器

二级空间配置器

二级空间配置器即为内存池

当容器申请内存时,内存池就分给容器对应字节的内存。但当容器用完内存时,不能单独释放这一小块内存,当时申请的多大内存就要释放多大内存,为了管理这些用完的内存,二级空间配置器加入了哈希桶(开散列)

索引以8字节为间隔到128字节,当容器将内存还回来时,就会根据大小选择挂在哪个索引下面,当后续有容器想要申请内存时,就会先从哈希桶内查找有无匹配的内存

若容器申请的内存在哈希桶中没有,从内存池中申请时,也不会只切出对应字节的内存,而是直接切出20个该对象内存,返回一个,剩下19个挂在哈希桶下面。

由于容器申请的内存一般都为小块内存,二级空间配置器就是专门为了解决申请小块内存而出现的,因此这样做可以通过批量预分配显著减少系统调用频率,从而在频繁申请小块内存的场景下提升性能

一个进程中有一个空间配置器,进程中所有的容器需要内存,都会找空间配置器

内存碎片问题

内碎片

在二级空间配置器中,如果申请的不是8字节的整数倍,也会向上内存对齐到8字节整数倍,而这样就会导致用于对齐的字节用不上,这就是内碎片问题

外碎片

当在堆上开辟了多个小块内存后,若后续其中的几块内存换回来,也有可能不连续

紫色×表示已释放,若此时再申请48字节内存,即使我们之前释放的空间也有48字节,但不是连续的,就不能用这两块空间申请,这就是外碎片问题,因此对于STL容器(常申请小块内存),就有了空间配置器来管理内存

内核中针对大量小块内存申请的碎片化问题,会使用slab分配器解决,它的结构类似于二级空间配置器

既然内核已经有slab分配器管理小块内存,为什么STL还需要二级空间配置器?

  • 内核是针对整个系统的所有程序的,并且每个都去堆申请,消耗特别大
  • STL的容器需要的全是小块内存,而且需求大小集中,因此自己设计一个自己用会效率更高,顺便解决内存碎片问题(解决了外碎片,但有内碎片)

到此这篇关于C++的IO流与STL的空间配置器详解的文章就介绍到这了,更多相关C++ IO流与STL空间配置器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅谈C语言共用体和与结构体的区别

    浅谈C语言共用体和与结构体的区别

    下面小编就为大家带来一篇浅谈C语言共用体和与结构体的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • C语言构建连连看游戏(矩阵方式)

    C语言构建连连看游戏(矩阵方式)

    这篇文章主要为大家详细介绍了C语言构建连连看游戏,采用矩阵方式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • C++实现判断一个字符串是否为UTF8或GBK格式的方法

    C++实现判断一个字符串是否为UTF8或GBK格式的方法

    这篇文章主要介绍了C++实现判断一个字符串是否为UTF8或GBK格式的方法,涉及C++针对字符编码的遍历、判断、编码转换等相关操作技巧,需要的朋友可以参考下
    2017-11-11
  • Qt6替代废弃QMediaPlaylist的解决方案

    Qt6替代废弃QMediaPlaylist的解决方案

    本文介绍了一种自定义的Qt6多媒体播放列表类,以兼容Qt6的新多媒体架构,该类支持三种播放模式,并自动绑定QMediaPlayer,实现了自动切换媒体的功能,作者还提供了代码实现,并通过实际项目中的BGMControl类进行了集成示例,需要的朋友可以参考下
    2026-04-04
  • c++回溯法解决1到9之间插入加减或空使运算结果为100

    c++回溯法解决1到9之间插入加减或空使运算结果为100

    编写一个在1,2,…,9(顺序不能变)数字之间插入+或-或什么都不插入,使得计算结果总是100的程序,并输出所有的可能性。例如:1 + 2 + 34 – 5 + 67 – 8 + 9 = 100
    2021-10-10
  • C++运算符重载的详细讲解

    C++运算符重载的详细讲解

    这篇文章主要给大家介绍了关于C++运算符重载的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • C语言代码实现扫雷小游戏

    C语言代码实现扫雷小游戏

    这篇文章主要为大家详细介绍了C语言代码实现扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • C语言宏定义使用分析

    C语言宏定义使用分析

    在宏定义中,“宏名称”和“宏字符串”是通过“空格”来区分的,某些朋友不要混淆了,接下来请祥看本文
    2012-12-12
  • 初识C++的const关键字,常量与常变量

    初识C++的const关键字,常量与常变量

    这篇文章主要为大家详细介绍了C++的const关键字,常量与常变量,使用数据库,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C/C++ Zlib库封装MyZip压缩类的详细过程

    C/C++ Zlib库封装MyZip压缩类的详细过程

    在软件开发中,文件的压缩和解压缩是一项常见的任务,而ZIP是一种被广泛应用的压缩格式,本文将聚焦于一个简化的C++实现,通过分析代码,我们将深入了解其设计和实现细节,感兴趣的朋友一起看看吧
    2023-11-11

最新评论