6

バッファリングされたストリームの場合、本では、バッファがいっぱいになるまで待ってからモニターに書き戻すと書かれています。例えば:

cout << "hi"; 
  1. 「バッファがいっぱいです」とはどういう意味ですか。

    cerr << "hi";
    
  2. 私の本では、送信されたものcerrはすべて標準エラー デバイスにすぐに書き込まれると書かれていますが、これはどういう意味ですか?

    char *ch;
    cin>> ch; // I typed "hello world";
    
  3. この例chでは、「hello」に割り当てられ、「world」は無視されますが、それはまだバッファにあり、将来のステートメントの結果に影響するということですか?

4

5 に答える 5

15

あなたの本はあまり役に立たないようです。

1) 出力ストリームは、バイトを に送信しますstd::streambuf。これにはバッファが含まれる場合があります。および によって使用される (から派生した)はstd::filebuf、通常、バッファリングされます。つまり、文字を出力しても、すぐに出力されるとは限りません。これはバッファーに書き込まれ、バッファーがいっぱいになった場合にのみ OS に出力されます。または、通常 はストリームを呼び出すことによって (直接または間接的に を使用して)、何らかの方法で明示的に要求します。ただし、これは異なる場合があります。への出力は と同期され 、ほとんどの実装は多かれ少なかれ forの規則に従い、出力が対話型デバイスに送られる場合はバッファリング戦略を変更します。streambufstd::ofstreamflush()std::endlstd::coutstdoutstdoutstd::cout

いずれにせよ、確信が持てず、出力が実際にプログラムを離れることを確認したい場合は、flush の呼び出しを追加するだけです。

2) あなたの本はここで間違っています。

バッファリング戦略の 1 つは次のとおりですunitbufstd::ostreamこれは、設定またはリセットできるのフラグ です (std::ios_base::set()および std::ios_base::unset()std::ios_baseは の基底クラスで std::ostreamあるため、オブジェクトでこれらの関数を呼び出すことができstd::ostream ます)。unitbufが設定されている場合 、すべての出力関数の最後にへのstd::ostream呼び出しが追加されるため、次のように記述します。flush()

std::cerr << "hello, world";

が設定されている場合、文字列内のすべての文字が出力された後、ストリームはフラッシュunitbufされます。起動時に、unitbufに設定されstd::cerrます。デフォルトでは、他のファイルには設定されていません。ただし、必要に応じて自由に設定または設定解除できます。on の設定を解除しないことをお勧めしますがstd::cerr、 がインタラクティブなデバイスに出力している場合std::coutは、そこに設定するのが非常に理にかなっています。

ここで問題になっているのは、streambuf. 通常、OS もバッファリングします。バッファが行うすべてのフラッシュは、文字を OS に転送することです。ofstreamこの事実は、トランザクションの整合性が必要な場合に直接使用できないことを意味します 。

3) を使用して文字列または文字バッファに入力する>>と、 std::istream最初に先頭の空白がスキップされ、次の空白まで入力されますが、次の空白は含まれません。標準の正式な用語では、ストリームから文字を「抽出」するため、それらが再び表示されることはありません(ストリームがサポートしている場合は、シークしない限り)。次の入力は、前の入力が中断されたところからピックアップされます。次の文字がバッファにあるか、ディスク上にあるかは、実際には関係ありません。

入力のバッファリングは、いくつかの異なるレベルで発生し、OS レベルでは、デバイスに応じて異なる形式をとるという点で、やや複雑であることに注意してください。通常、OS はファイルをセクターごとにバッファリングし、多くの場合、事前にいくつかのセクターを読み取ります。OS は、ファイルの終わりに遭遇しない限り、常に要求された数の文字を返します。ほとんどの OS は、キーボードを行単位でバッファリングします。つまり、行全体が入力されるまで読み取り要求から返されず、読み取り要求で現在の行の終わりを超えて文字が返されることはありません。

出力に std::ostreama を使用するのと同じ方法で、 1 を使用して個々の文字を取得します。の場合、通常は;になります。が 文字を要求すると、バッファに文字がある場合はバッファから文字が返されます。そうでない場合は、OS から 512 文字 (またはそのバッファ サイズが何であれ) を要求して、バッファを補充しようとします。上記のように、デバイスのバッファリング ポリシーに従って応答します。streambufstd::istreamstd::cinfilebufistreamfilebuf

いずれにせよstd::cin、 がキーボードに接続されていて、 を入力した場合、入力"hello world"したすべての文字が最終的にストリームによって読み取られます。(ただし、 を使用している場合>>は、表示されない空白がたくさんあります。)

于 2012-05-09T15:25:33.317 に答える
2

C++ のストリームは、効率を上げるためのバッファです。つまり、ファイルとコンソールの IO は、メモリ操作と比較して非常に低速です。

この C++ ストリームに対処するために、ファイルまたは出力に書き込むすべてのものを含むバッファ (メモリのバンク) があり、いっぱいになるとファイルにフラッシュされます。入力の場合は逆で、バッファが使い果たされると、より多くのフェッチが行われます。

以下の理由から、これはストリームにとって非常に重要です。

std::cout << 1 << "hello" << ' ' << "world\n";

非効率的なファイルへの4回の書き込みになります。

ただし、std::cout、cin、および cerr の場合、これらの型は実際にはデフォルトでバッファリングがオフになっており、std::printf および std::puts などと組み合わせて使用​​できるようになっています...

再度有効にするには (これをお勧めします):

std::ios_base::sync_with_stdio(false);

ただし、C スタイルのコンソール出力が false に設定されている場合は使用しないでください。そうしないと、問題が発生する可能性があります。

于 2012-05-09T15:01:51.113 に答える
2

小さなアプリで違いを自分で確認できます。

#include <iostream>
int main() {
    std::cout<<"Start";
    //std::cout<<"Start"<<std::endl; // line buffered, endl will flush.
    double j = 2;
    for(int i = 0; i < 100000000; i++){
        j = i / (i+1);
    }
    std::cout<<j;
    return 0;
}

2 つの「開始」ステートメントの違いを試してから、cerr に変更します。お気づきの違いは、バッファリングによるものです。

for ステートメントは私のリグで約 2 秒かかります。あなたのリグでは i < 条件を微調整する必要があるかもしれません。

于 2012-05-09T15:13:43.357 に答える
1

1)「バッファがいっぱい」とはどういう意味ですか。

バッファリングされた出力には、バッファと呼ばれるメモリの領域があります。この領域には、実際に出力に書き込まれる前に、書き出したものが保存されます。あなたが言うときcout << "hi"、文字列はおそらくそのバッファにコピーされるだけで、書き出されません。coutは通常、そのメモリがいっぱいになるまで待機してから、実際に書き込みを開始します。

これは、通常、実際にデータを書き始めるプロセスが遅いためです。そのため、すべての文字に対してそれを行うと、ひどいパフォーマンスが得られます。バッファは、プログラムがそれを頻繁に行う必要がなく、パフォーマンスが大幅に向上するように使用されます。

2)私の本では、cerrに送信されるものはすべて、すぐに標準エラーデバイスに書き込まれると書かれていますが、これは、「h」を送信してから「i」を送信することを意味しますか?

これは、バッファが使用されていないことを意味します。cerrは、すでに両方を持っているため、「h」と「i」を同時に送信する可能性があります。

3)この例では、chは「hello」に割り当てられ、「world」は無視されます。これは、chがまだバッファー内にあり、将来のステートメントの結果に影響を与えることを意味しますか?

これは実際にはバッファリングとは何の関係もありません。char *の演算子>>は、空白が表示されるまで読み取るように定義されているため、「hello」と「world」の間のスペースで停止します。しかし、はい、次にあなたが読むとき、あなたは「世界」を手に入れるでしょう。

(ただし、そのコードが実際のコードの言い換えではない場合は、テキストを未定義のメモリ位置に読み込んでいるため、未定義の動作になります。代わりに、次のようにする必要があります。

std::string s;
cin >> s;

)。

于 2012-05-09T15:12:37.597 に答える
0
  1. 端末への書き込みの各呼び出しは遅いため、遅いことを避けるために、特定の量のデータが入力されるか、バッファがfflushまたはstd :: endlで手動でフラッシュされるまで、データはメモリに保存されることがよくあります。この結果、予期したとおりにテキストが端末に書き込まれない場合があります。

  2. エラーメッセージのタイミングは通常の出力よりも重要であるため、パフォーマンスヒットは無視され、データはバッファリングされません。ただし、文字列は1つのデータで渡されるため、1回の呼び出し(ループ内のどこか)で書き込まれます。

  3. その世界はまだバッファにありますが、3行のプログラムで試してみることでこれを自分で証明するのは非常に簡単です。ただし、未割り当てのメモリに書き込もうとしているため、例は失敗します。代わりに、std::stringに入力を受け取る必要があります。

于 2012-05-09T15:10:06.860 に答える