std::cout是 的一個實體std::ostream。std::cout我可以在一個名為的檔案中看到宣告/usr/include/c /7/iostream:
extern ostream cout; /// Linked to standard output
并且std::ostream由 定義typedef std::basic_ostream<char> std::ostream。
更重要的是,您似乎無法創建std::ostream. 請參閱此演示代碼片段:
#include<iostream>
int main()
{
std::ostream os;
return 0;
}
以下是編譯器對上面代碼片段的抱怨:
In file included from /opt/compiler-explorer/gcc-4.9.0/include/c /4.9.0/iostream:39:0,
from <source>:1:
/opt/compiler-explorer/gcc-4.9.0/include/c /4.9.0/ostream: In function 'int main()':
/opt/compiler-explorer/gcc-4.9.0/include/c /4.9.0/ostream:384:7: error: 'std::basic_ostream<_CharT, _Traits>::basic_ostream() [with _CharT = char; _Traits = std::char_traits<char>]' is protected
basic_ostream()
^
<source>:5:18: error: within this context
std::ostream os;
^
問題來了,既然std::basic_ostream<_CharT, _Traits>::basic_ostream()被標記為受保護,那么如何std::cout創建呢?
CppReference 上的這個鏈接似乎不是很有意義。它并沒有清楚地告訴我如何std::cout實作以及如何std::cout由std::ostream. 據我所知,最相關的資訊是:
全域物件
std::cout和std::wcout控制輸出到與標準 C 輸出流相關聯的實作定義型別的流緩沖區(派生自std::streambuf)stdout。
僅此而已。
我正在Ubuntu努力gcc 4.9
感謝@NathanPierson。
他告訴我
std::basic_ostream有一個建構式,它接受一個指向std::basic_streambuf物件的指標。std::cout使用指向某個實作定義的派生類的實體的指標進行初始化std::basic_streambuf。
,這讓我更接近答案。
uj5u.com熱心網友回復:
std::cout 是如何創建的?
首先,來自https://en.cppreference.com/w/cpp/io/ios_base/Init:
std::ios_base::Init
此類用于確保默認 C 流(std::cin、std::cout 等)正確初始化和銷毀??。[...]
標頭的
<iostream>行為就好像它(直接或間接)定義了一個具有靜態存盤持續時間的 std::ios_base::Init 實體:[...]
嗯,讓我們做一個真實的代碼示例。我將使用GCC C 庫。從https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/include/std/iostream#L73,這是重要的部分:
// For construction of filebuffers for cout, cin, cerr, clog et. al.
static ios_base::Init __ioinit;
現在我們跳轉到ios_base::Init類的建構式,在https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/src/c++98/ios_init.cc#L85:
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);
當_S_refcount您從靜態類的建構式手動呼叫時ios_base::Init::Init();,它可以防止雙重初始化。
這stdio_sync_filebuf是一個內部緩沖區istream/ostream用于存盤輸入/輸出資料,在此處實作https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/include/ext/stdio_sync_filebuf.h #L56。它繼承自std::basic_streambuf.
所以cout是用as 引數就地構造的。stdio_sync_filebuf<char>這是這里提到的第一個建構式https://en.cppreference.com/w/cpp/io/basic_ostream/basic_ostream。
現在,因為這些東西是就地構建的,你可能想知道記憶體是如何分配的?從https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/src/c++98/globals_io.cc#L50:
// Standard stream objects.
// NB: Iff <iostream> is included, these definitions become wonky.
typedef char fake_istream[sizeof(istream)]
__attribute__ ((aligned(__alignof__(istream))));
typedef char fake_ostream[sizeof(ostream)]
__attribute__ ((aligned(__alignof__(ostream))));
fake_istream cin;
fake_ostream cout;
fake_ostream cerr;
fake_ostream clog;
這些物件只是char適當大小和適當對齊的空緩沖區。
是的,您可以__gnu_cxx::stdio_sync_filebuf在 GCC 上自己構建 ostream:
#include <fstream>
#include <ext/stdio_sync_filebuf.h>
int main() {
__gnu_cxx::stdio_sync_filebuf<char> mybuf_cout_sync(stdout);
std::ostream os(&mybuf_cout_sync);
os << "Hello world!\n";
return 0;
}
或者,為了便于移植,您將撰寫自己的類,并自己繼承std::streambuf并構造ostream它。網上有很多例子,例如這里https://stackoverflow.com/a/51250032/9072753。
uj5u.com熱心網友回復:
編譯器及其標準庫實作可以使用非標準功能進行協作,這些功能僅由程式員使用。
在這種情況下這不是必需的,因為有一個非常標準的公共建構式:
explicit basic_ostream(basic_streambuf<char_type, Traits>* sb);
如果你streambuf準備好了,你可以創建一個 type 的物件,ostream標準庫也可以。
那streambuf究竟是一個隱藏的實作細節,但在典型的實作中,它可能是從stdout(C 風格的<cstdio>檔案指標)構造的自定義類的物件。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/494297.html
