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++学习之Pair的使用方法

    谈谈C++学习之Pair的使用方法

    pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同,本篇详细的介绍了Pair的使用方法和实例,有兴趣的同学可以了解一下。
    2016-12-12
  • C语言算法练习之数组元素排序

    C语言算法练习之数组元素排序

    这篇文章主要为大家介绍了C语言算法练习中数组元素排序的实现方法,文中的示例代码讲解详细,对我们学习C语言有一定帮助,需要的可以参考一下
    2022-09-09
  • C语言中判断一个char*是不是utf8编码

    C语言中判断一个char*是不是utf8编码

    这篇文章主要介绍了C语言中判断一个char*是不是utf8编码的相关资料,需要的朋友可以参考下
    2017-06-06
  • matlab遗传算法求解车间调度问题分析及实现源码

    matlab遗传算法求解车间调度问题分析及实现源码

    这篇文章主要为大家介绍了matlab遗传算法求解车间调度问题解析,文中附含详细实现源码,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-02-02
  • C++中volatile关键字及常见的误解总结

    C++中volatile关键字及常见的误解总结

    这篇文章主要给大家介绍了关于C++中volatile关键字及常见的误解的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-05-05
  • C语言泛型编程实例教程

    C语言泛型编程实例教程

    这篇文章主要介绍了C语言泛型编程,针对泛型的用法做了深入浅出的实例介绍,是C程序设计中非常实用的技巧,需要的朋友可以参考下
    2014-09-09
  • 解析在main函数之前调用函数以及对设计的作用详解

    解析在main函数之前调用函数以及对设计的作用详解

    本篇文章是对在main函数之前调用函数以及对设计的作用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • c++中的const_cast用法大全

    c++中的const_cast用法大全

    const_cast转换符是用来移除变量的const或volatile限定符。对于后者,我不是太清楚,因为它涉及到了多线程的设计,今天重点给大家介绍c++中的const_cast用法大全,需要的朋友参考下吧
    2021-07-07
  • C++快速排序的分析与优化详解

    C++快速排序的分析与优化详解

    这篇文章主要介绍了C++快速排序的分析与优化,非常经典的算法,分析也较为详尽,需要的朋友可以参考下
    2014-08-08
  • QT实现FTP上传文件

    QT实现FTP上传文件

    这篇文章主要为大家详细介绍了QT实现FTP上传文件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08

最新评论