1

以下のプログラムの出力は次のとおりです。

1: foo strlen: 3
2:  strlen: 0
3: foo strlen: 3
4: foo strlen: 3
5:  strlen: 0
6:  strlen: 0

理解できない

  • なぜ1文字列を出力しますが、出力2しません
  • 3つのループの違いは何ですか

起源:

#include "stdafx.h"
#include <map>
#include <string>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    map<string, string> m;
    m["foo"] = "bar";

    const char * s;

    for(map<string, string>::iterator it = m.begin(); it != m.end(); it++)
    {
        pair<string, string> kvPair = *it;
        s = kvPair.first.c_str();
        printf("1: %s strlen: %d\n", s, strlen(s));
        break;
    }
    printf("2: %s strlen: %d\n", s, strlen(s));

    for(map<string, string>::iterator it = m.begin(); it != m.end(); it++)
    {
        s = (*it).first.c_str();
        printf("3: %s strlen: %d\n", s, strlen(s));
        break;
    }
    printf("4: %s strlen: %d\n", s, strlen(s));

    for(map<string, string>::iterator it = m.begin(); it != m.end(); it++)
    {
        s = ((pair<string, string>) (*it)).first.c_str();
        printf("5: %s strlen: %d\n", s, strlen(s));
        break;
    }
    printf("6: %s strlen: %d\n", s, strlen(s));

    return 0;
}

更新C++のバックグラウンドがほとんどないプログラマー向けの説明をいただければ幸いです。

4

3 に答える 3

5

最初の例では、 -loopのスコープで宣言されているc_str()onを呼び出します。が破棄されるため、ループを抜けると結果は無効になります。kvPairforforkvPair

c_str()2 番目の例では、マップ内の値を呼び出します。結果は、マップが破棄されたときにのみ無効になります。これは、_tmain(...)返されたときに発生します。

3 番目の例では、c_str()(ペアへのキャストによって作成された) 一時的なものを呼び出し、その一時的なものprintf("5...は呼び出される前に破棄されます。

説明

によって返されるポインタは、それが呼び出されたときにc_str()所有するメモリを指すため、それが破棄されると、ポインタへのアクセスは未定義の動作になります。stringstring

于 2012-07-12T06:28:19.937 に答える
3

部分的に偶然。

1/2 では、ループ内にローカル変数を作成し、値をマップから にコピーkvPairします。sこのコピーのデータを指すように設定します。ブロックを終了すると、コピーは破棄されます (デストラクタが呼び出されます)。いずれにせよ: breakgoto、例外、または単純にループ本体を終了して再度実行する — ループを通過するたびkvPairに、ループ本体の最後で破棄される新しい を取得します。 s内のデータを指し、 その後の(単にコピーするだけでも)kvPair.firstの使用skvPairhas been destructed は未定義の動作です。何が起こるかは、デバッグ チェックと最適化のレベルに応じて、またはプログラムのまったく無関係な側面に応じて異なる可能性があります。(一貫して空の文字列を取得する場合は、おそらく設計が不十分なデバッグ チェックが行われている可能性があります。適切に設計されたデバッグ チェックはすぐにクラッシュするため、エラーが表示されます。)

2/3 ではs、マップの実際のコンテンツで初期化するため、マップが破棄されるか、要素がマップから削除されるまで有効です。

4/5 では、テンポラリを作成します: typeを含む任意の type に対して、指定された初期化を使用して、T( initialization )type のテンポラリを構築します。(これは正確ではありません。たとえば が参照の場合、動作は異なります。)そして、この一時内のデータを指すように初期化します。一時オブジェクトの有効期間は、それを含む完全な式の終わりまでのみであるため、ステートメントの末尾のセミコロン (この場合は完全な式の終わり) での内容は無効になります。1/2 と同様に、この後に使用すると未定義の動作が発生します 。TTstd::pair<std::string, std::string>Tsss

于 2012-07-12T07:37:35.283 に答える
0

最初のループsはペアのデータを指しています - ペアはループ後に範囲外になるため、データは偽物です

2 番目と 3 番目のループはs、実際のコレクション内のデータを指しているため、範囲内にとどまります。

于 2012-07-12T06:28:50.950 に答える