2012-06-12 2 views
3

누출이 발생합니다. 무겁게 템플릿 화 된 tb::Stringtb::StringBase<char>의 typedef입니다.동적 문자열 크기를 조정하면 메모리 내가 아주 간단한 프로그램으로 시작

모든 것은 CRT 디버깅 유틸리티를 사용하여 메모리 누수를 확인하기 위해 컴파일됩니다. 출력은 다음과 같습니다.

Detected memory leaks! 
Dumping objects -> 
c:\users\sam\svn\dependencies\toolbox\headers\tbstring2.inl(38) : {442} normal block at 0x00D78290, 1 bytes long. 
Data: < > 00 
{131} normal block at 0x00C5EFA0, 52 bytes long. 
Data: <    > A0 EF C5 00 A0 EF C5 00 A0 EF C5 00 CD CD CD CD 
Object dump complete. 
Detected memory leaks! 
Dumping objects -> 
c:\users\sam\svn\dependencies\toolbox\headers\tbstring2.inl(38) : {442} normal block at 0x00D78290, 1 bytes long. 
Data: < > 00 
Object dump complete. 
The program '[2888] SAM_release.exe: Native' has exited with code 0 (0x0). 

tb : String (크기가 0 인)이 메모리 누수의 원인이되는 것처럼 보입니다.

#include <TBString.h> 

int main(int argv, char** argc) 
{ 
    tb::String test("Hello World!"); 

    return 0; 
} 

콜 스택을 원래 프로그램 :

  • 문자열 ""StringBase<char> 만들기 누설하지 않습니다이 프로그램으로 확인했다.
  • m_Length가 0
  • m_Maximum로 설정 m_Length + 1가 설정된다 (1).
  • 은 길이가 m_Maximum (1)으로 생성됩니다.
  • 은 지워지고 ""으로 채워집니다.
  • _AppendSingleStringBase<char>::_AppendDynSingle으로 설정됩니다.
  • 오버로드 된 연산자 StringBase<char>::operator =은 문자열 "Hello World!"
  • _AppendSingle과 함께 호출됩니다.
  • m_Lengthm_Maximum 1.
  • checklenm_Length + src_len + 1 (13)로 설정하고, 0이다.
  • m_Maximumchecklen (16)보다 커질 때까지 2를 곱합니다.
  • StringBase<char>::Resize 함수가 새로운 최대 값으로 호출됩니다.

크기 조정 기능 :

template <typename C> 
TB_INLINE StringBase<C>& StringBase<C>::Resize(int a_Maximum /*= -1*/) 
{ 
    if (!m_Data) 
    { 
     m_Maximum = (a_Maximum == -1) ? 4 : a_Maximum; 
     m_Data = new C[m_Maximum]; 
     StringHelper::Clear<C>(m_Data, m_Maximum); 
    } 
    else 
    { 
     int newmax = (a_Maximum == -1) ? (m_Maximum * 2) : a_Maximum; 

     C* temp = new C[newmax]; 
     StringHelper::Clear<C>(temp, newmax); 
     if (m_Length > 0) { StringHelper::Copy(temp, m_Data, m_Length); } 
     delete [] m_Data; 
     m_Data = temp; 

     m_Maximum = newmax; 
    } 

    return *this; 
} 

이 제가 생각하는 문제입니다. 자, 내 질문은 다음과 같습니다 :

CRT 디버거에서 메모리 누수를 유발하지 않고 어떻게 C++에서 메모리를 재 할당 할 수 있습니까?

생성자 :

TB_INLINE StringBase<char>::StringBase(const char* a_String) 
{ 
    m_Length = StringHelper::GetLength<char>(a_String); 
    m_Maximum = m_Length + 1; 
    m_Data = new char[m_Maximum]; 
    StringHelper::Clear<char>(m_Data, m_Maximum); 

    StringHelper::Copy<char, char>(m_Data, a_String, m_Length); 

    _AppendSingle = &StringBase<char>::_AppendDynSingle; 
    _AppendDouble = &StringBase<char>::_AppendDynDouble; 
} 

소멸자 :

TB_INLINE StringBase<char>::~StringBase() 
{ 
    if (m_Data) { delete [] m_Data; } 
} 

할당 연산자

TB_INLINE StringBase<char>& StringBase<char>::operator = (const char *a_String) 
{ 
    Clear(); 
    return (this->*_AppendSingle)(a_String); 
} 

추가] 기능 :

template<> 
TB_INLINE StringBase<char>& StringBase<char>::_AppendDynSingle(const char* a_String) 
{ 
    if (!a_String) { return *this; } 

    int src_len = StringHelper::GetLength<char>(a_String); 

    // check size 

    if (m_Maximum == -1) 
    { 
     m_Maximum = src_len + 1; 
     m_Data = new char[m_Maximum]; 
     StringHelper::Clear<char>(m_Data, m_Maximum); 
     m_Length = 0; 
    } 

    int checklen = m_Length + src_len + 1; 
    if (checklen > m_Maximum) 
    { 
     while (checklen > m_Maximum) { m_Maximum *= 2; } 
     Resize(m_Maximum); 
    } 

    // append 

    strcat(m_Data, a_String); 

    // new length 

    m_Length += src_len; 

    return *this; 
} 
,174,

참고 : std::string 또는 std::vector을 사용하고 싶지 않습니다.이 기능을 수정하고 싶습니다.

+1

그 질문은 대부분'tb :: String' 클래스에 관한 것 같습니다. 이 카드는 지금 자신의 카드인가요, 아니면 도서관의 카드인가요? – leftaroundabout

+0

'tb :: String'이란 무엇입니까? 진지한 것, 해킹 한 것? –

+0

'tb :: String'은 제 자신의 동적 문자열 클래스입니다. 필요한 경우 전체 소스를 게시 할 수 있지만 가장 관련성이 높은 비트를 붙여 넣었다고 생각합니다. – knight666

답변

0

이것은 길어 보일 것입니다.

먼저 내 정신을 확인하기로 결정했습니다. CRT 메모리 디버거가 올바르게 작동합니까?

int* src_test = new int[10]; 
for (int i = 0; i < 10; i++) { src_test[i] = i; } 
int* dst_test = new int[10]; 
for (int i = 0; i < 10; i++) { dst_test[i] = src_test[i]; } 
delete [] src_test; 

정확하게 40 바이트 누수를보고합니다. 이 라인은 누수를 수정합니다 :

delete [] dst_test; 

그래, 또 뭐야? 어쩌면 해체업자가 호출되지 않았을 수도 있습니다. 함수에 넣자 :

void ScopeTest() 
{ 
    tb::String test("Hello World!"); 
    test = "Hello World! Again!"; 
} 

작동하지만 누출됩니다. deconstructor가 호출되었음을 절대적으로 확인합시다.

void ScopeTest() 
{ 
    tb::String* test = new tb::String("Hello World!"); 
    *test = "Hello World! Again!"; 
    delete test; 
} 

여전히 누출. 자, = 연산자는 무엇을합니까? 그것은 지우고 덧붙인다. 수동으로 해보겠습니다 :

void ScopeTest() 
{ 
    tb::String* test = new tb::String("Hello World!"); 
    test->Clear(); 
    test->Append("Hello World! Again!"); 
    delete test; 
} 

동일한 결과이므로 운영자와 아무런 관련이 없습니다. 나는

void ScopeTest() 
{ 
    tb::String* test = new tb::String("Hello World!"); 
    test->Append("Hello World! Again!"); 
    delete test; 
} 

좋아, 그것은 ... 잠시 기다려 ... 나는 Clear을 제거한 경우 무슨 일이 일어날 것이라고 생각해, 무엇을? 누출이 아닙니까? 그러면 Clear은 무엇을합니까?

template <> 
TB_INLINE StringBase<char>& StringBase<char>::Clear() 
{ 
    if (m_Data) 
    { 
     StringHelper::Clear<char>(m_Data, m_Maximum); 
    } 

    m_Length = 0; 

    return *this; 
} 

그건 ... 무해한 것입니다. 그러나 그것을 주석으로 풀어 봅시다.

template <> 
TB_INLINE StringBase<char>& StringBase<char>::Clear() 
{ 
    /*if (m_Data) 
    { 
     StringHelper::Clear<char>(m_Data, m_Maximum); 
    } 

    m_Length = 0;*/ 

    return *this; 
} 

동일한 결과, 누출 없음. 다시 Clear 번으로 전화를 끊으십시오.

void ScopeTest() 
{ 
    tb::String* test = new tb::String("Hello World!"); 
    //test->Clear(); 
    test->Append("Hello World! Again!"); 
    delete test; 
} 

누출 바이트 다시 ...

하지만 잠깐 두 번째, 여전히 tb::String을 삭제이야? 본문이 주석 처리 되더라도 길이는 0으로 설정되고 데이터는 제로로 출력됩니다. 어떻게, 어떤 ...

좋아, 컴파일러, 이제이을 컴파일 보자 :

/*template <> 
TB_INLINE StringBase<char>& StringBase<char>::Clear() 
{ 
    if (m_Data) 
    { 
     StringHelper::Clear<char>(m_Data, m_Maximum); 
    } 

    m_Length = 0; 

    return *this; 
}*/ 

하! 그 사람이 보여줄거야! 오 기다려라. .. 그것은 아직도 컴파일되고, 달린다.

동일한 파일의 다른 버전을 사용하고 있습니까? 아니요,이 컴퓨터에는 TBString2.hTBString2.inl의 버전이 하나만 있습니다 ...

오.

오, 잠깐.

오 갓맘.

이것이 더 좋을 것이라고 생각하지 않습니다.

나는 이것을 3 시간 쓴 사람을 살해 할 것입니다.

Project Game -> Toolbox.lib 

오 기다려. 그게 나야.

TL : 나는 문자열 클래스의 오래된 빌드에 연결되어 메모리 누수를 포함한 모든 종류의 이상한 동작을 일으켰습니다.

0

할당을 수행 한 후 생성자에서 초기화 된 바이트가 누출됩니다. 누수를 디버깅하려면 할당을 수행 할 때 디버거를 단계별로 실행하십시오. m_Data 변수에 감시 점을 설정하여 값이 변경 될 때마다 디버거가 중지되도록하는 것이 유용 할 수 있습니다.