14

cout を使用してデバッグ情報を出力するプログラムがあります。コードは、静的グローバル変数の初期化、つまりプログラム実行のかなり早い段階で実行されます。独自のビルド スクリプトを使用してプログラムをビルドすると、最初に cout を使用したときに segfault が発生します (文字列リテラルのみが cout にシフトされるため、値にすることはできません)。valgrind を使用して、無効な場所への以前の書き込みをチェックしましたが、何もありません (また、それらの書き込みを生成する可能性のあるコードもありません。出力の前にあまり多くのことを行いません)。ソース コードを Eclipse プロジェクトにコピーし、Eclipse 組み込みビルダーでビルドすると、すべて正常に動作します。でコンパイルされた奇妙なビルダー設定は使用しませんでした-ggdb -std=c++0x。これらは 2 つのフラグのみです。

では、以前に無効な書き込みがなかった場合、文字列リテラルを含む cout が segfault になる理由は何でしょうか? ビルド構成はこれにどのように影響しますか?

(この例は、eclipse ビルダーを使用している場合と同様に、マシンで正常にコンパイルされるため、最小限の例を提供できず申し訳ありません)

編集:スタックトレースは次のとおりです。

0x00007ffff7b6d7d1 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib   /x86_64-linux-gnu/libstdc++.so.6
(gdb) backtrace
#0  0x00007ffff7b6d7d1 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00007ffff7b6dee9 in std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2  0x00007ffff7b6e2ef in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) ()
  from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00000000004021be inTest::fill (this=0x6120f8, funcs=...) at inTest.cpp:92

最後のフレームは私のコードです。92行目は次のように単純に書かれています:

std::cout << "Test";
4

3 に答える 3

15

Luchian が指摘したようstd::coutに、 の最初のインスタンスios_base::Initが構築される前に使用することはできません。ただし、インスタンスを定義する必要はありません。含む<iostream>だけで十分です。

初期化の順序は、1 つの翻訳単位内で定義されます<iostream>静的インスタンスを持つすべてのファイルの先頭に含める場合は、問題ありません。ただし、静的オブジェクトのコンストラクターが別の翻訳単位の関数を呼び出し、出力がその翻訳単位にある場合、出力を行う翻訳単位だけに含めるだけでは不十分<iostream> です。静的変数が定義されている翻訳単位に含める必要があります。何も出力しない場合でも。

于 2012-09-07T13:32:35.370 に答える
14

std::cout静的ストレージ内のオブジェクトです。に入る前に初期化されることが保証されていmainますが、コード内の他の statics の前にあるとは限りません。静的初期化順序の大失敗のようです。

掘り下げた後:

27.4.2.1.6 クラス ios_base::Init

Init ();

3) 効果: クラス Init のオブジェクトを構築します。init_cnt がゼロの場合、関数は init_cnt に値 1 を格納し、オブジェクト cin、cout、cerr、clog (27.3.1)、wcin、wcout、wcerr、および wclog (27.3.2) を構築して初期化します。いずれの場合も、関数は init_cnt に格納されている値に 1 を追加します。

于 2012-09-07T13:07:46.343 に答える
0

静的変数の初期化は無人地帯です。そこで重要な作業を行わないようにすれば、問題を回避できます。静的変数をSingleton パターンでラップして、初期化を最初に使用するまで延期できるようにする必要があるかもしれません。

于 2012-09-07T13:37:33.650 に答える