yohhoyの日記

技術的メモをしていきたい日記

標準入出力とbasic_ios::tie

標準入力ストリームcinと標準エラーストリームcerrは、それぞれ標準出力ストリームcoutに結び付け(tie)られている。N3337 27.4.2/p2, p5, 27.5.5.3/p1より該当箇所を引用。*1

istream cin;
2 After the object cin is initialized, cin.tie() returns &cout. (snip)

ostream cerr;
5 After the object cerr is initialized, cerr.flags() & unitbuf is nonzero and cerr.tie() returns &cout. (snip)

basic_ostream<charT,traits>* tie() const;
1 Returns: An output sequence that is tied to (synchronized with) the sequence controlled by the stream buffer.

この標準入出力ストリームの結合により、下記のようなコードがプログラマの意図通り動作する。つまりキーボードからの入力待ちよりも前に、コンソールへの文字列出力が保証される。

std::cout << "1+2=";
int answer;
std::cin >> answer;  // 文字列"1+2="が出力された後で標準入力を待機

一方でcin読み出しのたびにcoutフラッシュ操作が行われるため、直接ファイルストリーム(fstream)を用いた場合に比べて標準入出力を介したファイル処理は速度が遅くなる。上記の動作が不要であれば、下記コードにてcincoutの結び付けを解除する。

std::cin.tie(0);


N3337 27.7.2.1.3/p2, 27.7.3.4/p2より一部引用(下線部は強調)。

namespace std {
  template <class charT, class traits = char_traits<charT> >
  class basic_istream<charT,traits>::sentry { /*(snip)*/ };
}

explicit sentry(basic_istream<charT,traits>& is, bool noskipws = false);
2 Effects: (snip) First, if is.tie() is not a null pointer, the function calls is.tie()->flush() to synchronize the output sequence with any associated external C stream. Except that this call can be suppressed if the put area of is.tie() is empty. Further an implementation is allowed to defer the call to flush until a call of is.rdbuf()->underflow() occurs. If no such call occurs before the sentry object is destroyed, the call to flush may be eliminated entirely. (snip)

namespace std {
  template <class charT, class traits = char_traits<charT> >
  class basic_ostream<charT,traits>::sentry { /*(snip)*/ };
}

explicit sentry(basic_ostream<charT,traits>& os);
2 (snip) If os.tie() is not a null pointer, calls os.tie()->flush().

入力ストリームbasic_istreamに対する書式付き入力(operator>>)や書式無し入力(getなど)において、basic_istream::sentryによる flush 処理が行われうる。(27.7.2.2.1/p1, 27.7.2.3/p1)
出力ストリームbasic_ostreamに対するシーク操作(tellp, seekp)、書式付き出力(operator<<)、書式無し出力(putなど)において、basic_ostream::sentryによる flush 処理が行われうる。(27.7.3.5/p1, 27.7.3.6.1/p1, 27.7.3.7/p1)

関連URL

*1:ワイドストリーム wcout, wcin, wcerr についても同様に結び付けられている。