2012-07-12 4 views
1

프로그램의 출력은 아래 1 인쇄 문자열하지만 2이되지 않고 C++ 반복자 수수께끼는

  • 않는 이유는

    • 을 이해하지 못하는

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

      무엇인지의 차이 세 개의 루프는

    출처 :

    #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와 프로그래머에 대한 설명은 ++ 배경 감상 할 수있다.

  • +0

    Nitpick> : "stdafx.h", 누락 된 ,'std ::'가 없습니다. ;-) – DevSolar

    +1

    'kvPair.first.c_str()'는 일시적이지 않습니까? – DevSolar

    +0

    'kvPair'와 같이 온 것입니다. –

    답변

    3

    부분적으로 우연히. 당신은 루프 내에서 지역 변수를 만들 1/2에서

    , 복사kvPair에지도 밖으로 값 . 이 사본의 데이터를 가리 키도록 s을 설정했습니다. 블록을 종료하면 복사본이 소멸됩니다 (소멸자가 호출 됨). 어떤 방법으로 : break, goto, 예외, 또는 단순히 루프 본문 을 마무리하고 루프를 통해 다시 — 그것을 통해 때마다 것, 당신은 루프 몸의 끝 부분에 파괴되는 새로운 kvPair을 얻을. s은 이 소멸 된 후 내부의 데이터를 가리키며 (단순히 복사하는 경우도 있음)의 사용은 정의되지 않으므로 동작이 정의되지 않습니다.아무 일도 일어나지 않을 것이며, 디버그 검사 및 최적화 수준에 따라 이 달라 지거나 프로그램과 전혀 관련이없는 부분에 따라 이 발생할 수 있습니다. (당신이 지속적으로 빈 문자열을 얻을 경우, 아마 계속 확인하는 몇 가지 잘못 설계 디버그있다. 잘 설계 디버그 검사는 즉시 충돌이 발생할 것입니다, 그래서 당신은 오류를 볼 것입니다.) 2/3에서

    , s을지도의 실제 내용으로 초기화하므로지도가 소멸 될 때까지 유효한 이거나 해당 요소가 지도에서 삭제됩니다.

    4/5에서는 임시을 만듭니다 T(initialization) 유형 std::pair<std::string, std::string>을 포함, 모든 종류의 T에 대한 을 부여한 초기화를 사용하여 입력 T의 일시적를 구축합니다. 예를 들어, 이 참이 아니며, 예를 들어 T이 참조 인 경우 동작이 다릅니다. 그리고 s을 초기화하여이 임시 데이터 내의 데이터를 가리 키도록합니다. 임시의 유효 기간은 이 포함 된 전체 표현식의 끝 부분까지이므로 의 내용은 세미콜론 (이 경우 전체 표현식의 끝)을 종료 할 때 유효하지 않게됩니다. 1/2에서와 마찬가지로 s 을 사용하면 정의되지 않은 동작이 발생합니다.

    +0

    그래서 올바르게 이해한다면,'* it'을 직접''* it ''을 사용하는 대신에 지역 변수에 저장하면, 1) 쌍의 인스턴스와 2) 완전한 복사본을 생성 할 것입니다.), 'first'와 'second'두 멤버 문자열의. 마지막으로,'c_str()'메소드는 새로운 것은 아무것도 만들지 않고 그냥 문자열이 무효가 되 자마자 유효하지 않은 포인터가 될 문자열을 가리키는 포인터를 반환합니다. 그게 옳은가? –

    +0

    @EugeneBeresovksy 거의. 일반적으로 C++은 _value_ 의미론을 사용합니다. 새로운 변수, 임시 변수 등은 원본의 _copies_이며 두 개의 객체는 완전히 별개입니다. (예외는 참조를 사용할 때 예외이다.) 그러나'c_str()'_은 새로운 객체를 생성한다. 그러나'char const *'유형의 객체; C++에서 포인터는 객체입니다. –

    +0

    그래서 c_str()은 새로운 포인터를 생성하지만 문자열 값의 일부 위치에 대한 포인터입니다. 포인터가 범위를 벗어나면 다시 계산됩니다. 변종 2는 그렇지 않고지도의 쌍에 직접 액세스하는 반면 (이 경우 올바르게 가정하면) 변형 1이 쌍을 복사한다는 사실에 익숙해 져야 할 필요가 있습니다. 그러면 나에게 모두 의미가있을 것입니다. –

    5

    첫 번째 예에서는 -loop의 범위에 선언 된 kvPair에서 c_str()을 호출합니다. kvPair이 삭제 되었기 때문에 for 루프가 종료되면 결과가 유효하지 않게됩니다.

    두 번째 예제에서는 c_str()을 맵의 값으로 호출합니다. _tmain(...)이 반환 될 때 발생하는지도가 파괴되면 결과는 무효화됩니다.

    세 번째 예에서는 c_str()을 임시로 (쌍을이 용하여 생성 한) 호출하고 printf("5...을 호출하기 전에 해당 임시를 소멸시킵니다.

    설명

    가에 호출되는 string가 소유 한 일부 메모리에 c_str() 점에 의해 반환되는 포인터, 그래서 string이 파괴 될 때, 포인터를 액세스하는 정의되지 않은 동작입니다.

    +0

    C++ 학습자에게 무슨 일이 일어나는지 신경 써 주시겠습니까? 왜냐하면'kvPair'가 임시 적이기 때문에 (왜냐하면 그것은 for 루프 안에서 선언 되었기 때문입니다)'kvPair.first.c_str()'의 결과는's'에 저장 될 때 왜 일시적일까요? 고리? –

    +1

    C + +로 말하면,'kvPair'는 임시적인 것이 아닙니다. "임시"라는 용어는 완전한 표현식의 끝에서 파괴 된 이름없는 객체들 (예를 들어 그가 세 번째 루프에서 사용하는 것과 같이)을 위해 예약되어 있습니다. –

    +0

    @JamesKanze : 네 말이 맞아, 나는 다시 말하려고 노력할 것이다. – Kleist

    0

    s가 쌍의 데이터를 가리키는 첫 번째 루프 - 쌍 루프 이후 범위를 벗어나 있으므로 데이터가 가짜 인

    두 번째 및 세 번째 루프는 s 실제 수집 데이터를 가리키고있다 - 그래서 그것은 범위에 남아 있습니다

    +1

    세 번째 루프는's'를 임시로 가리키며, 이는 전체 표현식의 끝에서 소멸됩니다. –