none
CSimpleStringT::GetString 의 반환값은 메모리의 어느 영역에 저장되어있습니까? RRS feed

  • 질문

  • 안녕하십니까.

    저는 C++ 공부를 하고 있습니다.

    CSimpleStringT 의 GetString 함수는 null 로 종료되는 문자열을 반환하는 함수입니다.

    그리고 반환형이 PCXSTR 로 되어 있는데, const wchar_t* 을 여러번 typedef 한 결과 였습니다.

    종합해보면 저 함수의 리턴값은 문자열의 시작 주소를 가리키고 있다는 것입니다.

    저는 문자열 주소를 반환하는 방법으로 동적할당된 char 배열의 첫주소를 반환하는 방법 밖에 모릅니다. 정적 할당된 배열의 주소를 반환하면, 함수가 반환되면서 자원을 해제하니 접근 위반으로 알고 있습니다. (혹시 참조자를 사용하는 방법이 있습니까?)

    그래서 GetString 함수의 반환값이 동적할당된 영역을 가리킬 것으로 예상하고, 이를 delete 하는 코드를 다음과 같이 작성해 봤습니다. (편의를 위해 SimpleStringT 클래스를 상속받는 CStringA 클래스를 사용했습니만, 같은 시그니처의 새로운 함수를 정의하지는 않아 결과와는 무관한 것으로 알고 있습니다.)


    CStringA * myStr = new CStringA("Hi");
    const char * myPtr = myStr->GetString();
    printf("%s\n", myPtr);
    delete[] myPtr ;

     

    그랬더니 dbgheap.c 파일의 extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer 함수의 중단점에 걸리게 된 뒤, Debug assertion failed! 메시지가 뜨며 프로그램이 종료되었습니다. 잘은 모르지만 heap 영역을 가리키지 않는 포인터에 대해 delete 를 해서 생기는 문제 같습니다.


    일어난 일을 시간 순으로 썼더니 질문이 잘 정리되지 않은 것 같습니다.

    제 궁금증은 다음과 같습니다. CSimpleStringT::GetString 이 문자열을 반환하는 방식과 그 문자열이 메모리의 어느 영역에서 어떠한 라이프 사이클을 지니는지 알고 싶습니다. 반환하는 방식에 대해서는 간단한 예제 코드를 주시면 이해와 응용에 더 도움이 될 것 같습니다.

    +내용 추가

    잘 생각해보니, 저는 그냥 함수의 반환에 대해서 이해가 부족합니다. 일단 그 부분을 공부해 보겠습니다.


    • 편집됨 lightkill826 2018년 6월 1일 금요일 오전 4:04
    2018년 5월 31일 목요일 오전 7:31

모든 응답

  • 위 테스트 코드에서 myPtr에 대해 delete[] 연산자를 사용하셨는데, 이것은 용법이 좀 이상한 것 같습니다.

    const char * myPtr = myStr->GetString(); 라는 라인을 실행할 때, myPtr은 myStr이 가지고 있는 m_pszData라고 하는 멤버 변수의 포인터를 그대로 가져갑니다. 따라서 myPtr에 대해서 delete를 수행하려고 하면 이는 곧 myStr이 가진 m_pszData에 대한 delete를 수행한다는 뜻이되는데, 이렇게 접근이 되지를 않겠죠. 본체인 myStr을 delete하는 것이 올바른 용법이라고 봅니다.

    또한 new에는 delete, new[]에는 delete[]로 대응이 되어야 합니다.

    myStr은 new로 생성되었으므로, 올바른 코드는 아래와 같이 되어야 할 것입니다.

    CStringA * myStr = new CStringA("Hi");
    const char * myPtr = myStr->GetString();
    printf("%s\n", myPtr);
    delete myStr ;

    2018년 6월 5일 화요일 오전 5:51
  • CSimpleStringT::GetString 함수의 실제 구현은 다음과 같습니다.

    PCXSTR GetString() const throw()
    {
    	return( m_pszData );
    }

    단순히 내부적으로 문자열을 담고있는 포인터를 const 타입으로 반환하는 함수죠.

    그러므로 CSimpleStringT::GetString 함수가 반환한 const char* 포인터의 라이프 사이클은 다음과 같습니다.

    1. CSimpleStringT 객체의 라이프사이클 동안 유효

    2. CSimpleStringT 객체가 담는 문자열이 변경되지 않는 동안 유효

    1, 2번 조건이 모두 만족되어야 const char* 포인터가 유효하다고 볼 수 있습니다.

    실제로는 CString 클래스가 COW(Copy On Write)를 구현하고 있기 때문에 더 복잡하지만 저렇게만 이해하셔도 무방합니다.

    그리고 작성하신 소스 코드에서 CSimpleStringT::GetString 함수가 반환한

    const char* 포인터를 delete 하셨는데 저렇게 사용하시면 절대 안됩니다.

    문자열을 복사해서 반환하는 것이 아니라 내부 포인터를 직접 반환하기 때문입니다.

    만약 char* 포인터를 얻어서 이 포인터를 이용해 문자열을 조작하고 싶으시다면

    CSimpleStringT::GetBuffer 함수를 사용하시면 됩니다.

    단, 이 경우에도 반환된 포인터를 절대 delete 하시면 안됩니다.


    2018년 6월 8일 금요일 오전 12:08