C++之“流”-第2课-C++和C标准输入输出同步

news2024/9/20 20:33:18

为什么C++和C的标准输入输出不同步时,数据会混乱?同步会带来多大性能损失?为什么说这个损失通常不用太在乎?

0. 课堂视频

C++之“流”-第2课:和C输入输出的同步

1. 理解cin和cout的类型与创建过程

std::cout 是std::ostream类型的一个变量;而 std::ostream是std::basic_ostream<char>模板类的类型别名( typedef )。std::cin是std::isteram类型的一个变量,而std::istream是std::back_istream<cahr>模板类的类型别名。两个模板类中的 “char” 参数,表明二者都是基于普通 字符(char)作为最小输出或输入单位。如果改为 wchar_t,则以UNICODE字符串作为基本输入输出单位。

正如上一节课所说,std::ostream和std::istream都是抽象概念的流,无法直接创建对应的输出或输入流对象。

注意,C++中的“抽象”概念,和 Java 这样更加纯粹的“面向对象”的编程语言有所不同。Java 中的“抽象”,通常使用:“什么实事都不做,只负责定要求” 的接口(interface)表达。C++中有更多不同的方式来表达抽象概念,可以同样“什么事都不做,只负责定要求”的纯虚类,也可以是“做了很多基础的事,但禁用了特定构建方法”的方式。两种方式的共同表现是:不让用户直接创建对象。

std::ostream和std::istream对外开放的构造方法,都要求一个“流缓存区/stream_buf”入参。以输出为例,我们可以:

  • 设计并实现一个内存输出缓存区,传入后以得到一个内存输出流的基本功能;
  • 设计并实现一个文件输出缓存区,传入后以得到一个文件输出流的基本功能;
  • 设计并实现一个网络输出缓存区,传入后以得到一个网络输出流的基本功能;

那么,为std::istream的构造函数传入一个键盘输入流缓存区,就能得到一个标准输入流,即std::cin;而为std::ostream传入一个屏幕输出流缓存区,就能得到一个标准输出流,即std::cout。但实际上,C++程序中的std::cin和std::cout对象,都是C++库自动创建出来的,并且不允许用户手工创建二者。为什么呢?因为对一个程序来说,标准输入设施应该只有一个,标准输出设施也应该只有一个;如果用户自己创建,就挡不住有用户创建出一打标准输入流或标准输出流了。

在Windows的控制台(console)或Linux下的终端(terminal)里,键盘被称为程序的标准输入设备,屏幕被称为程序的标准输出。并且,无论一台电脑接多少个键盘(少见),在逻辑上都会被当作一个键盘;同理,无论一台电脑接多少个屏幕(常见),在逻辑上也都会被当作一个屏幕。因此,cin 和 cout 本质上是一种“单例”,即整个程序中,只能一个标准输入流,一个标准输出流。

这种“一个程序里,某种类型的对象只有一个”的逻辑的实现,有专门的,称为“单例模式”的设计模式来实现。C++实现 cin 和 cout 的单例保障倒很简单:使用默认构造函数(没有任何入参)来创建特定对象,再把该默认构造函数的访问权限设置为私有(private)或保护的(protected),在gc++的实现中使用的是后者。标准库内部可以通过 “友元”加“派生”的方式,实现对基类受保护的默认构造函数的调用。

一旦调用std::ostream的默认构造函数,由于没有入参,也就没有外部传入的输出缓存区,此时标准库将自动创建标准输出流的缓存区,从而创建出标准输出流,即:std::cout对象。标准输入流的创建过程与此类型,同样是调用默认构造函数,然后自行创建、关联和键盘输入缓存区,从而创建出 std::cin。

以上调用过程都是在程序主函数 main() 开始之前,就执行完毕,因此我们的程序在一开始就能够方便地使用std::cin和std::cout。事实上,在 main() 之前我们就可以使用了。如果在 main() 函数之前就开始执特定代码,这是C++的另一个知识点,不在此讲解。

2. 数据输入输出次序冲突问题的出现

到现在,一切看起来很完美:cin和cout是自动创建的,并且各自只会有一份,不会冲突……但是,考虑到C++的一个重要的历史使命:兼容C语言,问题就来了——

C 语言有自己的输入输出机制,并且本质上,底层也需要用到输入或输出缓存区。上一节课我们说过,这个缓存区本质是一个数据队列,一个“有次序保障”的数据队列。C++尽管做到了一个程序只有一个C++输入流或一个C++输出流,但加上C的队列,现在,一个C++程序会有两个输入队列、两个输出队列。

C/C++两套输入输出队列

这就有点像现实生活中的某种排队现象:入口或出口只有一个,但人们排了两条队,两条队伍各自的内部数据都有次序保障,但是,当门就在眼前,两条队伍如何通过一个门呢?无论是互相礼让,还是争先抢后,都无法保障复原原始的数据次序。

3. 混合输入,同步对比不同步

代码:

#include <cstdio> // C 语言的标准输入输出库
#include <iostream>

using namespace std;

int main()
{
    ios_base::sync_with_stdio(false); // 不同步!!!

    int i, j;

    scanf("%d", &i); //用C的方式输入  i
    cin >> j; // 用C++的方式输入 j

    cout << i << ", " << j << endl;

    return 0;
}

4. 混合输出,同步对比不同步

代码:

#include <cstdio>
#include <iostream>

using namespace std;

int main()
{
	ios_base::sync_with_stdio(false);

	for (int i=0; i<3; ++i)
	{
		printf("hello from printf!\n");
		cout << "hello from cout.\n";
	}

	return 0;
}

5. 同步与不同步性能对比

代码:

#include <ctime>
#include <cstdio>
#include <iostream>

using namespace std;

int main()
{
    ios::sync_with_stdio(false);

    clock_t beg = clock();

    for (int i=0; i<30000; ++i)
    {
        cout << "hello world.";
    }


    clock_t end = clock();
    cout << "\n" << (end - beg) * 1000 / CLOCKS_PER_SEC << "ms." <<endl;


    return 0;
}

注意,程序使用 sync_with_stdio(false) 取消 C++和C的标准输入输出同步,该操作是不可逆的,即后续无法通过 sync_with_stdio(true) 恢复 同步。

6. 为什么不用太在乎C++标准输入输出的性能?

C++常用以写以下程序:

类型典型应用描述大致占比输入输出性能
后台服务或底层组件网络服务、防火墙不直接面向用户,不使用标准输入输出25%不在乎
GUI程序Photoshop、Office、游戏使用系统GUI作为输入输出20%不在乎
基础工具命令行文件处理工具:压缩、图片处理虽然在命令行运行,但几乎没有输入输出15%不在乎
简单命令行工具各类命令行客户端程序:libcurl,文件列表低频使用标准输入输出20%不在乎
非性能敏感的控制台应用用户开发的简单命令行应用,比如处理excel表格性能不敏感15%不在乎
性能敏感的控制台应用信息学竞赛程序、远程日志监控等性能敏感,大量标准输入输出操作会影响程序性能5%在乎

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Css 提高 - 获取DOM元素

目录 1、根据选择器来获取DOM元素 2.、根据选择器来获取DOM元素伪数组 3、根据id获取一个元素 4、通过标签类型名获取所有该标签的元素 5、通过类名获取元素 目标&#xff1a;能查找/获取DOM对象 1、根据选择器来获取DOM元素 语法&#xff1a; document.querySelector(css选择…

C/C++运行时库和UCRT系统通用运行时库总结及问题实例分享

目录 1、概述 2、不同版本的Visual Studio对应的运行时库说明 3、在Windbg10.0安装目录中获取UCRT通用运行时库 4、微软官网对UCRT通用运行时库的相关说明 5、使用Visual Studio 2017开发软件初期遇到的UCRT通用运行时库问题 6、如何查看软件依赖了哪些C/C运行时库&#…

vueRouter路由总结

https://blog.csdn.net/qq_24767091/article/details/119326884

奇门遁甲古籍《烟奇要览》

《烟奇要览》 全书共178页 时间有限&#xff0c;仅上传部分图片&#xff01;

js深入理解对象的 属性(properties)的特殊 特性(attributes)

对象 js对象 // 构造一个对象 let obj {}; let obj new Object(); 我们知道js中一切皆对象&#xff0c;对象是一个键值对集合&#xff08;key: value)&#xff0c;一个键(key)对应一个值(value)&#xff0c;而每个键都是这个对象的属性&#xff0c;我们可以通过对象的属性来…

在CentOS 8上卸载与安装MySQL 8的详细步骤

关键词&#xff1a;MySQL 8安装、CentOS 8、YUM源配置、卸载MySQL、MySQL残留文件删除、首次登录MySQL临时密码、服务状态检查、MySQL社区服务器 阅读建议&#xff1a;本文适合需要在CentOS 8操作系统上部署最新MySQL 8数据库的系统管理员或开发者阅读。文中步骤简洁清晰&#…

ResizeObserver loop completed with undelivered notifications.

报错信息 ResizeObserver loop completed with undelivered notifications. 来源 在用vue3 element-plus写项目的时候报的错&#xff0c;经过排查法&#xff0c;发现是element-plus的el-table组件引起的错误。 经过初步排查&#xff0c;这个错误并不是vue以及element-plus…

springboot投票统计管理系统的设计与实现-计算机毕业设计源码73598

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设投票统计管理系统。 …

最新扣子(Coze)实战教程:扣子​使用基础,完全免费,快来学习吧~

&#x1f9d9;‍♂️ 诸位好&#xff0c;吾乃斜杠君&#xff0c;编程界之翘楚&#xff0c;代码之大师。算法如流水&#xff0c;逻辑如棋局。 &#x1f4dc; 吾之笔记&#xff0c;内含诸般技术之秘诀。吾欲以此笔记&#xff0c;传授编程之道&#xff0c;助汝解技术难题。 &#…

电脑由于ntdll.dlI丢失导致exe崩溃有什么解决办法?解决ntdll.dll丢失问题

相信有一些用户正在面临一个叫做“ntdll.dll丢失”的问题&#xff0c;这种情况多半发生在试图运行某个程序时&#xff0c;系统会提示一条错误消息&#xff1a;“程序无法启动&#xff0c;因为计算机中丢失了ntdll.dll”。那么&#xff0c;为何ntdll.dll文件会丢失&#xff0c;又…

OrangePi Kunpeng Pro 开箱测评之一步到喂

前情提要&#xff1a;大家好&#xff0c;我是Samle。有幸接到 CSDN 发来的测评邀请&#xff0c;下面针对 OrangePi Kunpeng Pro 开发板进行一些实践操作&#xff0c;让大家能更好的上手这块板子。 以下内容来自 官方说明 OrangePi Kunpeng Pro采用4核64位处理器AI处理器&#…

JavaScript数组重构数据,数组转换成对象

在后端返回的数据中&#xff0c;可能不太满意&#xff0c;所以需要自己重构数据。 原始数据 let arr [ {title:"光头强",age:18,id:"0"}, {title:"孙悟空",age:18,id:"9"}, {title:"熊大",age:18,id:"0"}, {ti…

RAG-GPT实践过程中遇到的挑战

引言 前面介绍了使用RAG-GPT和OpenAI快速搭建LangChain官网智能客服。有些场景&#xff0c;用户可能无法通过往外网访问OpenAI等云端LLM服务&#xff0c;或者由于数据隐私等安全问题&#xff0c;需要本地部署大模型。本文将介绍通过RAG-GPT和Ollama搭建智能客服。 RAG技术原理…

第2章 物理层

王道学习 考纲内容 &#xff08;一&#xff09;通信基础 信道、信号、带宽、码元、波特、速率、信源与信宿等基本概念&#xff1b; 奈奎斯特定理与香农定理&#xff1b;编码与调制&#xff1b; 电路交换、报文交换与分组交换&#xff1b;数…

【Redis】Widows 和 Linux 下使用 Redis

Redis 简述 1.缓存 缓存就是将数据存放在距离计算最近的位置以加快处理速度。缓存是改善软件性能的第一手段,现代 CPU 越来越快的一个重要因素就是使用了更多的缓存,在复杂的软件设计中,缓存几乎无处不在。大型网站架构设计在很多方面都使用了缓存设计。 2.Redis Redis …

Java8Stream

目录 什么是Stream? IO流&#xff1a; Java8Stream&#xff1a; 什么是流&#xff1f; stream图解 获取流 集合类&#xff0c;使用 Collection 接口下的 stream() 代码 数组类&#xff0c;使用 Arrays 中的 stream() 方法 代码 stream&#xff0c;使用 Stream 中的…

智慧水坝:科技变革的里程碑

在曾经的水利工程领域&#xff0c;水坝只是为了水资源的调配和控制&#xff0c;提供一定的安全储备。然而&#xff0c;随着现代科技的不断发展&#xff0c;传统的水坝已经不再是单一的水源控制工程&#xff0c;而是变成了一个充满智慧与创新的生态系统。智慧水坝的概念已经超越…

【机器学习】SUTRA引领多语言处理

在人工智能的浪潮中&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术一直是备受瞩目的焦点。随着全球化和信息时代的到来&#xff0c;多语言处理能力成为了评估NLP技术优劣的重要标准。近期&#xff0c;一款名为SUTRA的多语言大型语言模型架构引起了业界的广泛关注。它…

CRLF注入漏洞

1.CRLF注入漏洞原理 Nginx会将 $uri进行解码&#xff0c;导致传入%0a%0d即可引入换行符&#xff0c;造成CRLF注入漏洞。 执行xss语句 2.漏洞扩展 CRLF 指的是回车符(CR&#xff0c;ASCII 13&#xff0c;\r&#xff0c;%0d) 和换行符(LF&#xff0c;ASCII 10&#xff0c;\n&am…

Java项目:基于SSM框架实现的企业人事管理系统单位人事管理系统【ssm+B/S架构+源码+数据库+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的企业人事管理系统单位人事管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观…