2016-07-25 9 views
6

私は、次のC++コードについて少し混乱しています:初期化は

#include <iostream> 

using namespace std; 

void test(const string& str) 
{ 
    static const char * const c = str.c_str(); 
    cout << c << endl; 
} 

int main(int argc, char* argv[]) 
{ 
    test("Hello"); 
    test("Nooo"); 
    return 0; 
} 

変数c以来staticconstとして宣言され、これは一度だけ初期化するべきではありませんし、その初期値を保ちますプロセスが完了するまで?この推論によると、私は次の出力期待していた:

Hello 
Hello 

をしかし、私は得た:変数cの値が2つの機能の間で変更された理由を

Hello 
Nooo 

あなたは明確にできても、それにもかかわらず呼び出します変数はconstですか?

答えて

14

プログラムにはの定義されていない動作があります。

あなたはtestから"hello"を渡す

は、一時的な std::stringオブジェクトが作成され、その文字列 cから(文字列オブジェクトのデータへのポインタだけです)構築されます。

関数呼び出しが終了すると、テンポラリstd::stringオブジェクトが破棄され、cがダングリングポインタになります。もう一度使用すると、未定義の動作になります。

2番目のテンポラリstd::stringオブジェクトのデータは、最初のものと全く同じメモリアドレスを持つため、cはそのデータを指しています。これはまったく保証されません。

+0

実際には未定義ではありません。 **参照解除**は未定義です。逆参照されると常に有効なアドレスを持つので、有効なプログラムです。 – StoryTeller

+3

@StoryTeller、 'cout << c << endl;'はポインタを逆参照します。 –

+1

@StoryTeller出力演算子は逆参照を使用します。 –

1

コードに未定義の動作があるため、結果が異なる場合があります。 UBは、test("Hello");という呼び出しが静的ローカル変数に代入されるために作成されるためです。このテンポラリは、呼び出しが終了した後に破棄されるため、テスト関数内のポインタはダングリングしています。それを使用すると、未定義の動作が発生します。

メモリマネージャが同じメモリ領域を再利用する可能性があるため、結果にHelloとNoooが表示されます。