7

著者はこのコードをタイトルで提示しましたA bus error on my platform

#include <fstream>
#include <iostream>

int main()
{
    std::ofstream log("oops.log");
    std::cout.rdbuf(log.rdbuf());
    std::cout << "Oops!\n";
    return 0;
}

文字列「Oops!\n」がファイル「oops.log」に出力されます。コードはcoutのstreambufを復元しませんが、VS2010はランタイムエラーを報告しませんでした。

4

3 に答える 3

10

logとはバッファを共有しているためstd::cout、そのバッファはおそらく 2 回解放されます (1 回logはスコープ外に出るとき、次にもう 1 回はプログラムの終了時に)。

これにより未定義の動作が発生するため、彼のマシンではバス エラーが発生するのに、あなたのマシンでは警告なしに失敗する正確な理由を特定するのは困難です。

于 2013-02-13T18:21:20.457 に答える
5

他の回答はこれについて何をすべきかについて言及していないので、ここでそれを提供します。coutが管理することになっているバッファを保存して復元する必要があります。例えば:

#include <fstream>
#include <iostream>

// RAII method of restoring a buffer
struct buffer_restorer {
    std::ios &m_s;
    std::streambuf *m_buf;

    buffer_restorer(std::ios &s, std::streambuf *buf) : m_s(s), m_buf(buf) {}
    ~buffer_restorer() { m_s.rdbuf(m_buf); }
};

int main()
{
    std::ofstream log("oops.log");
    buffer_restorer r(std::cout, std::cout.rdbuf(log.rdbuf()));
    std::cout << "Oops!\n";
    return 0;
}

これで、プログラムの最後に破棄されるcout前に'バッファが置き換えられると、そのバッファが破棄されると正しいことが起こります。coutcout


標準のioを単純にリダイレクトする場合、通常、環境にはすでにそれを実行する機能があります(たとえば、シェルでのioリダイレクト)。上記のコードではなく、おそらくプログラムを次のように実行します。

yourprogram > oops.log

また、覚えておくべきことの1つstd::coutは、他のグローバル変数と同じ欠点を持つグローバル変数です。それを変更したり使用したりする代わりに、通常の手法を使用してグローバル変数をまとめて回避することをお勧めします。たとえば、std::ostream &log_outputコードを直接使用する代わりに、パラメータを渡してそれを使用することができcoutます。

于 2013-02-13T19:07:39.410 に答える
3

あなたのプログラムには未定義の動作があります。

グローバル オブジェクトのデストラクタは、coutスコープ外に出るとストリーム バッファを削除しますlog。これは、まったく同じストリーム バッファを所有する にも当てはまります。したがって、同じオブジェクトを 2 回削除しています。

プログラムに未定義の動作がある場合、ハード ドライブのフォーマットからエラーなしの終了まで、あらゆることが起こります。

たとえば、私のプラットフォームでは、プログラムは から戻った後、無限ループに入りますmain()

于 2013-02-13T18:22:28.077 に答える