首页 > 编程语言 > 详细

C++标准库中的std::endl究竟做了什么?

时间:2019-11-13 16:39:25      阅读:138      评论:0      收藏:0      [点我收藏+]

先抓出std::endl的源代码:

/**

 *  @file  ostream

 *  @brief  Write a newline and flush the stream.

 *

 *  This manipulator is often mistakenly used when a simple newline is

 *  desired, leading to poor buffering performance.  See

 *  http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt11ch25s02.html

 *  for more on this subject.

*/

template<typename _CharT, typename _Traits>

inline basic_ostream<_CharT, _Traits>&

endl(basic_ostream<_CharT, _Traits>& __os)

{

  return flush(__os.put(__os.widen(‘\n‘)));

}

 

可以看到endl实际是名字空间std中的一个全局内联函数记住std::endl是一个函数),它做了两件事:

1) 输出一个换行符(为何要输出一个换行符,如果不输出会怎么样?);

2) 调用flush

 

继续看flush这个函数(也是std名字空间内的全局内联函数):

/**

 *  @brief  Flushes the output stream.

 *

 *  This manipulator simply calls the stream‘s @c flush() member function.

*/

template<typename _CharT, typename _Traits>

inline basic_ostream<_CharT, _Traits>&

flush(basic_ostream<_CharT, _Traits>& __os)

{

  return __os.flush(); // 注意这里的os不是操作系统的意思,而是类basic_ostream的缩写

}

 

进一步查看std::basic_ostream::flush的代码:

/**

 *  @file  ostream.tcc

*/

template<typename _CharT, typename _Traits>

basic_ostream<_CharT, _Traits>&

basic_ostream<_CharT, _Traits>::flush()

{

  // _GLIBCXX_RESOLVE_LIB_DEFECTS

  // DR 60. What is a formatted input function?

  // basic_ostream::flush() is *not* an unformatted output function.

  ios_base::iostate __err = ios_base::goodbit;

 

  __try

  {

    // 刷新发生在pubsync,底层调用的是LIBC库函数fflush

    if (this->rdbuf() && this->rdbuf()->pubsync() == -1)

      __err |= ios_base::badbit;

  }

  __catch(__cxxabiv1::__forced_unwind&)

  {

    this->_M_setstate(ios_base::badbit);

    __throw_exception_again;

  }

  __catch(...)

  {

    this->_M_setstate(ios_base::badbit);

  }

  if (__err)

    this->setstate(__err);

  return *this;

}

 

下段小代码,可以看到两个帮助释疑的调用栈,:

$ cat xxx.cpp

#include <iostream>

int main() {

  std::cout << std::endl;

  return 0;

}

 

写换符符:

#0  0x00007ffff72e0840 in write () from /lib64/libc.so.6

#1  0x00007ffff726cfb3 in _IO_new_file_write () from /lib64/libc.so.6

#2  0x00007ffff726e41c in __GI__IO_do_write () from /lib64/libc.so.6

#3  0x00007ffff726e7f3 in __GI__IO_file_overflow () from /lib64/libc.so.6

#4  0x00007ffff726ac49 in putc () from /lib64/libc.so.6

#5  0x00007ffff7b694c6 in std::ostream::put(char) () from /lib64/libstdc++.so.6

#6  0x00007ffff7b69712 in std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&) ()

   from /lib64/libstdc++.so.6

#7  0x0000000000400803 in main () at xxx.cpp:3

 

刷新流:

#0  0x00007ffff7262030 in fflush () from /lib64/libc.so.6

#1  0x00007ffff7b68d5e in std::ostream::flush() () from /lib64/libstdc++.so.6

#2  0x0000000000400803 in main () at xxx.cpp:3

 

实际上,还可以看到更多,如全局对象std::coutstd::cerrstd::clog等的析构:

#0  0x00007ffff7262030 in fflush () from /lib64/libc.so.6

#1  0x00007ffff7b68d5e in std::ostream::flush() () from /lib64/libstdc++.so.6

#2  0x00007ffff7b41bc8 in std::ios_base::Init::~Init() () from /lib64/libstdc++.so.6

#3  0x00007ffff722fa69 in __run_exit_handlers () from /lib64/libc.so.6

#4  0x00007ffff722fab5 in exit () from /lib64/libc.so.6

#5  0x00007ffff7218c0c in __libc_start_main () from /lib64/libc.so.6

#6  0x0000000000400729 in _start ()

 

Init析构的同时析构cout等:

/**

 *  @file  ios_init.cc

*/

ios_base::Init::~Init()

{

  // Be race-detector-friendly.  For more info see bits/c++config.

  _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_S_refcount);

  if (__gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, -1) == 2)

  {

    _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_S_refcount);

    // Catch any exceptions thrown by basic_ostream::flush()

    __try

    {

      // Flush standard output streams as required by 27.4.2.1.6

      cout.flush();

      cerr.flush();

      clog.flush();

    

  #ifdef _GLIBCXX_USE_WCHAR_T

      wcout.flush();

      wcerr.flush();

      wclog.flush();

  #endif

    }

    __catch(...)

    {

    }

  }

}

 

文件ios_init.cc其它相关函数源码:

1) std::ios_base::Init的构造函数

ios_base::Init::Init()

{

  if (__gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 1) == 0)  //  防止重复初始化

  {

    // Standard streams default to synced with "C" operations.

    _S_synced_with_stdio = true;

 

    new (&buf_cout_sync) stdio_sync_filebuf<char>(stdout);

    new (&buf_cin_sync) stdio_sync_filebuf<char>(stdin);

    new (&buf_cerr_sync) stdio_sync_filebuf<char>(stderr);

 

    // The standard streams are constructed once only and never destroyed.

    new (&cout) ostream(&buf_cout_sync);

    new (&cin) istream(&buf_cin_sync);

    new (&cerr) ostream(&buf_cerr_sync);

    new (&clog) ostream(&buf_cerr_sync);

    cin.tie(&cout);

    cerr.setf(ios_base::unitbuf);

    // _GLIBCXX_RESOLVE_LIB_DEFECTS

    // 455. cerr::tie() and wcerr::tie() are overspecified.

    cerr.tie(&cout);

 

#ifdef _GLIBCXX_USE_WCHAR_T

    new (&buf_wcout_sync) stdio_sync_filebuf<wchar_t>(stdout);

    new (&buf_wcin_sync) stdio_sync_filebuf<wchar_t>(stdin);

    new (&buf_wcerr_sync) stdio_sync_filebuf<wchar_t>(stderr);

 

    new (&wcout) wostream(&buf_wcout_sync);

    new (&wcin) wistream(&buf_wcin_sync);

    new (&wcerr) wostream(&buf_wcerr_sync);

    new (&wclog) wostream(&buf_wcerr_sync);

    wcin.tie(&wcout);

    wcerr.setf(ios_base::unitbuf);

    wcerr.tie(&wcout);

#endif

 

    // NB: Have to set refcount above one, so that standard

    // streams are not re-initialized with uses of ios_base::Init

    // besides <iostream> static object, ie just using <ios> with

    // ios_base::Init objects.

    __gnu_cxx::__atomic_add_dispatch(&_S_refcount, 1);

  }

}

 

2) 全局函数ios_base::sync_with_stdio

bool

ios_base::sync_with_stdio(bool __sync)

{

  // _GLIBCXX_RESOLVE_LIB_DEFECTS

  // 49.  Underspecification of ios_base::sync_with_stdio

  bool __ret = ios_base::Init::_S_synced_with_stdio;

 

  // Turn off sync with C FILE* for cin, cout, cerr, clog iff

  // currently synchronized.

  if (!__sync && __ret)

  {

    // Make sure the standard streams are constructed.

    ios_base::Init __init;

 

    ios_base::Init::_S_synced_with_stdio = __sync;

 

    // Explicitly call dtors to free any memory that is

    // dynamically allocated by filebuf ctor or member functions,

    // but don‘t deallocate all memory by calling operator delete.

    buf_cout_sync.~stdio_sync_filebuf<char>();

    buf_cin_sync.~stdio_sync_filebuf<char>();

    buf_cerr_sync.~stdio_sync_filebuf<char>();

 

#ifdef _GLIBCXX_USE_WCHAR_T

    buf_wcout_sync.~stdio_sync_filebuf<wchar_t>();

    buf_wcin_sync.~stdio_sync_filebuf<wchar_t>();

    buf_wcerr_sync.~stdio_sync_filebuf<wchar_t>();

#endif

 

    // Create stream buffers for the standard streams and use

    // those buffers without destroying and recreating the

    // streams.

    new (&buf_cout) stdio_filebuf<char>(stdout, ios_base::out);

    new (&buf_cin) stdio_filebuf<char>(stdin, ios_base::in);

    new (&buf_cerr) stdio_filebuf<char>(stderr, ios_base::out);

    cout.rdbuf(&buf_cout);

    cin.rdbuf(&buf_cin);

    cerr.rdbuf(&buf_cerr);

    clog.rdbuf(&buf_cerr);

 

#ifdef _GLIBCXX_USE_WCHAR_T

  new (&buf_wcout) stdio_filebuf<wchar_t>(stdout, ios_base::out);

  new (&buf_wcin) stdio_filebuf<wchar_t>(stdin, ios_base::in);

  new (&buf_wcerr) stdio_filebuf<wchar_t>(stderr, ios_base::out);

  wcout.rdbuf(&buf_wcout);

  wcin.rdbuf(&buf_wcin);

  wcerr.rdbuf(&buf_wcerr);

  wclog.rdbuf(&buf_wcerr);

#endif

  }

  return __ret;

}

 

前面提到的endl为何要输出一个换行符,这是因为fflush只是将数据刷到标准输出,标准输出本身也是有缓存的,而这个换行符的作用是让数据sync,因为标准输出是字符型设备,对应的是行缓存_IOLBF line buffered)。

是否可将标准输出设置为全缓存_IOFBF fully buffered)了?答案是不可以,因为标准输出是字符设备Character Device,只能顺序读取),并不是块设备Block Device,支持随机存取)。因此下列代码即使已将标准输出设置为全缓存,但仍会不缓存立即输出,因为输出的字符串最后跟了换行符:

$ cat eee.cpp

#include <stdio.h>

int main(void) {

  char buf[BUFSIZ];

  setvbuf(stdin, buf, _IOFBF, BUFSIZ);

  printf("Hello, world!\n");

  getchar();

  return 0;

}

 

附问题:如何在GDB中调试跟踪std::cout

C++标准库中的std::endl究竟做了什么?

原文:https://www.cnblogs.com/aquester/p/11850495.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!