简体   繁体   English

应该始终使用std :: endl吗?

[英]Should std::endl always be used?

I am jumping from C into C++ with the help of the book C++ Primer (5th edition) where the author states the following: 在本书C ++ Primer (第5版)的帮助下,我将从C跳入C ++,作者在其中指出:

Programmers often add print statements during debugging. 程序员经常在调试过程中添加打印语句。 Such statements should always flush the stream. 此类语句应始终刷新流。 Otherwise, if the program crashes, output may be left in the buffer, leading to incorrect inferences about where the program crashed. 否则,如果程序崩溃,则输出可能留在缓冲区中,从而导致有关程序崩溃位置的错误推断。

But posts online suggest otherwise; 但是网上发布的建议则相反; some say constant flushing of the buffer is bad for the program and causes performance issues. 有人说不断刷新缓冲区对程序不利,并导致性能问题。

My questions: 我的问题:

  1. When should you use std::endl ? 什么时候应该使用std::endl
  2. Is the author wrong or did I misunderstand any part of what he stated? 作者是错误的还是我误解了他所说的内容?
  3. Can you give any real-world scenarios where flushing the output stream is necessary? 您能否给出需要刷新输出流的任何现实情况?

PS 聚苯乙烯

  1. What does flushing the buffer mean? 刷新缓冲区是什么意思?

Debug output should be written to std::cerr ; 调试输出应写入std::cerr ; it's unit buffered, so every character gets flushed. 它是单位缓冲的,所以每个字符都会被刷新。 There is rarely a need for std::endl , and getting in the habit of using it will lead to mysteriously slow code. 很少需要std::endl ,养成使用它的习惯会导致代码缓慢而神秘。 Just use '\\n' unless you know you need to flush the buffer. 除非您知道需要刷新缓冲区,否则只需使用'\\n'即可。

Point 4 and Point 3 点4和点3

Starting with point 4 because everything else hinges on it and point 3 because it is tightly related. 从点4开始,因为其他所有内容都取决于它,而点3因为它紧密相关。

When you flush the stream, you are taking all data stored by the stream and writing it to the underlying medium represented by the stream. 刷新流时,将获取流存储的所有数据并将其写入流所表示的基础介质中。

When it is flushed it is done, committed and ready to be observed by the outside world (More or less. The operating system and the hardware backing the stream may also delay the write, but there isn't much you can do about that). 刷新后,它便已完成,提交并准备好供外界观察(或多或少。支持流的操作系统和硬件也可能会延迟写入,但是对此您无能为力) 。 You can't read it until it has been flushed. 在将其刷新之前,您无法阅读。 If it's never flushed, you can't read it. 如果从未刷新过,则无法阅读。

The thing is you do not want to write to IO very often because anything that goes out of the CPU takes an ungodly amount of time compared to that which stays inside the CPU. 问题是您不希望经常写IO,因为与CPU内部相比,从CPU中取出的所有内容花费的时间都不长。 Tens of thousands of times slower sometimes. 有时会慢几万倍。 Inside the CPU you have gigahertz and parallel buses moving data 32 or more bits at a time. 在CPU内部,有千兆赫兹和并行总线,一次可移动32位或更多位数据。 Outside you have megahertz often moving a single bit at a time. 在外面,兆赫经常一次移动一点。

Take a file as a classic example. 以文件为例。 Not only is drive access running at a fraction of a speed of the CPU, but if every byte goes directly to a disk, then for every byte you may have to 驱动器访问不仅以CPU速度的几分之一运行,而且如果每个字节都直接进入磁盘,那么对于每个字节,您可能必须

  1. find that byte's analogue on the disk. 在磁盘上找到该字节的类似物。
  2. load the sector around that byte into memory. 将该字节周围的扇区加载到内存中。 So instead of moving one byte, you may be moving a few hundred or thousand. 因此,您可能要移动数百或数千个字节,而不是移动一个字节。 Usually 512 bytes or 4096 bytes. 通常为512字节或4096字节。
  3. write the byte into the sector in memory 将字节写入内存中的扇区
  4. write the sector in memory back to the disk 将内存中的扇区写回到磁盘

Brutal. 野蛮。 Imagine doing this a few hundred or a few thousand times to write a single string. 想象一下这样做几百或几千次以编写单个字符串。 But what if you only wrote the string when it got too big to hold or you were done? 但是,如果仅在字符串太大而无法保存或完成时才写字符串怎么办? What if you wrote in sectors rather than bytes? 如果您写扇区而不是字节怎么办? Then you could 那你可以

  1. find that byte's analogue's sector on the disk. 在磁盘上找到该字节的类似物扇区。
  2. write the stored sector to the disk 将存储的扇区写入磁盘

One operation for potentially thousands of byte in one shot. 一次可能对数千个字节进行一次操作。

Point 2 点2

Point 2 goes back to point four/three's you can't read what you don't flush. 第2点回到第4点/第3点,您无法阅读未冲洗的内容。 If you want to see a particular output on the screen and you want to see it now, you flush. 如果要在屏幕上看到特定的输出并且现在要查看,请刷新。 If you want to get a debug message out before the program crashes, and likely terminates without getting those last few absolutely essential messages onto the screen, you flush. 如果您想在程序崩溃之前发出调试消息,并且可能在没有将最后几条绝对必要的消息显示到屏幕的情况下终止,请刷新。 History is full of programmers looking in the wrong place for a bug because they didn't get those last few unflushed error messages. 历史上到处都是程序员在错误的地方寻找错误,因为他们没有得到最后几条未出错的错误消息。

You are trading program speed for the relative certainty that you will see an important message when you need to see it. 您以相对确定的速度交易程序,以确保您在需要查看重要消息时能够看到它。

Point 1 点1

Point 1 calls back to point 2. std::endl is both an end of line and an instruction to flush the stream. 点1调用返回点std::endl既是行尾,又是刷新流的指令。 You use it sparingly and only when you need both an end of line and a flush. 仅当需要行尾和冲洗时才少量使用它。 If you don't need a flush, just send and end of line: '\\n' . 如果不需要冲洗,只需发送并在行尾添加'\\n'

Take Pete Becker's advice and use std::cerr for errors and debugging where possible. 接受Pete Becker的建议,并在可能的情况下使用std::cerr进行错误和调试。 That's what it was built for. 这就是它的用途。 It operates on brute force and ignorance. 它依靠蛮力和无知运作。 It's painful. 这是痛苦的。 It's slow. 太慢了 And it almost always works. 而且它几乎总是有效。

Both the author and the posts are right. 作者和帖子都正确。

stream << std::endl is actually stream << '\\n' << std::flush . stream << std::endl实际上是stream << '\\n' << std::flush Explicit flushing has performance drawbacks, and this is why you shouldn't use it in performance-critical situations. 显式刷新具有性能缺陷,这就是为什么您不应该在性能关键的情况下使用它。 You rarely think about such negligible performance issues while debugging, so it actualy is a good practice to explicitly flush debug output. 你很少去想在调试这样微不足道的性能问题,所以它actualy 一个很好的做法,明确地冲洗调试输出。

By default std::cout is linked to stdout , which is... 默认情况下, std::cout链接到stdout ,即...

fully buffered if and only if the stream can be determined not to refer to an interactive device. 当且仅当可以确定该流不引用交互式设备时,才完全缓冲。

(C99, 7.19.3 Files, paragraph 7.) (C99,7.19.3文件,第7段。)

This means, if your output is sent to terminal, std::endl vs. "\\n" makes no difference in the first place. 这意味着,如果您的输出发送到终端,则std::endl"\\n"区别就没有任何区别。 ;-) ;-)


Regarding your actual question: 关于您的实际问题:

Both is true: 两者都是正确的:

  • unflushed output buffers can lead to incorrect inferences about where the program crashed 未缓冲的输出缓冲区可能导致错误推断程序在哪里崩溃
  • flushing of output buffers affects performance 刷新输出缓冲区会影响性能

This only becomes a problem once you add "always". 一旦添加“ always”,这只会成为问题。

When should you use std::endl ? 什么时候应该使用std::endl

When you want to flush the buffer. 当您刷新缓冲区时。

Is the author wrong or did I miss understand any part of what he stated? 作者是错误的还是我想念他所说的内容的一部分?

I think absolute quantifiers like "always", "all", "never" etc. should be taken with a grain of salt as far as style / design / etc. is concerned. 我认为,就样式/设计/等而言,绝对量词(如“ always”,“ all”,“ never”等)应加一点盐。

(Exception: Never invoke undefined behaviour. ;-) ) (例外: 切勿调用未定义的行为。;-))

Can you give any real world scenarios for actual need of flushing the output stream? 您能否给出实际的实际情况来冲洗输出流?

Whenever not having the latest output actually appear would not be acceptable. 每当没有最新输出实际出现时,都是不可接受的。 Whether this is the case in any given scenario is a judgement call. 在任何给定情况下是否都是这种情况,是一个判断电话。

Personally, I would consider production / transaction logs to be more critical than debug logs... 就个人而言,我认为生产/事务日志比调试日志更为关键...

1) When should you use std::endl ? 1)什么时候应该使用std :: endl?

When you want to be sure that the buffer is immediately flushed. 当您想要确保立即清除缓冲区时。

2) Is the author wrong or did i miss understand any part of what he stated? 2)作者是错的还是我想念他所说的内容的一部分?

No, the author is correct, and so are you. 不,作者是正确的,你也是。

3) can you give any real world scenarios for actual need of flushing the output stream? 3)您能给出实际需要冲洗输出流的任何实际情况吗?

When a particual string is written to the stream lots of times in a short amount of time std::endl might indeed cause performance loss because of the needless flushing of the buffer every time. 当particual字符串写入流很多次在很短的时间量std::endl确实造成性能损失因为不必要的冲洗可能缓冲每一次。 However, when it comes to printing lines that are added for the sole purpose of debugging you should always flush the buffer. 但是,当涉及仅出于调试目的而添加的打印行时,应始终刷新缓冲区。 Then again, if you're debugging an application with just print lines without using a debugger you're doing something wrong in the first place. 再说一次,如果您仅使用打印行调试应用程序而没有使用调试器,则首先是在做错事。

You should never use std::endl . 您永远不要使用std::endl This is a cargo-cult which must vanish. 这是一种必须消失的货运崇拜。 Gives you nothing but performance drawback. 除了性能上的缺点外,什么都没有给您。 Just make it a muscle memory: always "\\n" , never std::endl . 使其成为肌肉记忆:始终为"\\n" ,从不std::endl

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM