2

나는 이것을 몇 시간 동안 알아 내려고 노력해 왔으며, 나는 지혜로 끝까지 노력하고 있습니다. 누군가 내가 잘못하고 있다고 말할 수 있다면 분명 감사 할 것입니다.연산자를 구현할 때 delete [] (힙 손상) 사용 =

문자열의 기본 기능을 에뮬레이트하기위한 간단한 클래스를 작성했습니다. 클래스의 멤버는 문자 포인터를 (동적으로 생성 된 문자 배열을 포인트) 데이터 및 정수 strSize 포함 (문자열, 산세 터미네이터의 길이를 보유하고 있습니다.)

나는 새로운 을 사용하고 있기 때문에을 삭제하면 복사 생성자 및 소멸자가 구현되었습니다. 내 문제는 연산자 + =을 구현하려고 할 때 발생합니다. LHS 객체는 새 문자열을 올바르게 작성합니다. 심지어는 cout을 사용하여 인쇄 할 수도 있지만, 소멸자에서 데이터 포인터를 할당 해제하려고하면 문제가 발생합니다. 메모리 주소가 가리키는 "힙 손상이 감지되었습니다" 데이터 소멸자가 할당을 해제하려고 시도하는 배열.

#include <iostream> 

using namespace std; 

// Class to emulate string 
class Str { 
public: 

    // Default constructor 
    Str(): data(0), strSize(0) { } 

    // Constructor from string literal 
    Str(const char* cp) { 
     data = new char[strlen(cp) + 1]; 
     char *p = data; 
     const char* q = cp; 
     while (*q) 
      *p++ = *q++; 
     *p = '\0'; 
     strSize = strlen(cp); 
    } 

    Str& operator+=(const Str& rhs) { 
     // create new dynamic memory to hold concatenated string 
     char* str = new char[strSize + rhs.strSize + 1]; 

     char* p = str;     // new data 
     char* i = data;     // old data 
     const char* q = rhs.data;  // data to append 

     // append old string to new string in new dynamic memory 
     while (*p++ = *i++) ; 
     p--; 
     while (*p++ = *q++) ; 
     *p = '\0'; 

     // assign new values to data and strSize 
     delete[] data; 
     data = str; 
     strSize += rhs.strSize; 
     return *this; 
    } 


    // Copy constructor 
    Str(const Str& s) 
    { 
     data = new char[s.strSize + 1]; 
     char *p = data; 
     char *q = s.data; 
     while (*q) 
      *p++ = *q++; 
     *p = '\0'; 
     strSize = s.strSize; 
    } 

    // destructor 
    ~Str() { delete[] data; } 

    const char& operator[](int i) const { return data[i]; } 
    int size() const { return strSize; } 

private: 
    char *data; 
    int strSize; 
}; 

ostream& operator<<(ostream& os, const Str& s) 
{ 
    for (int i = 0; i != s.size(); ++i) 
     os << s[i]; 
    return os; 
} 


// Test constructor, copy constructor, and += operator 
int main() 
{ 
    Str s = "hello";  // destructor for s works ok 
    Str x = s;    // destructor for x works ok 
    s += "world!";   // destructor for s gives error 
    cout << s << endl; 
    cout << x << endl; 
    return 0; 
} 

편집 : 가속 C++ 문제 12-1

은 여기 내 전체 클래스와 테스트 프로그램입니다.

+0

이것은 몇 가지 분명한 질문 또는 '숙제'태그를 요구합니다. – sbi

답변

4

다음 코드 덩어리가 p를 배열 옆에 둡니다.

while (*p++ = *q++) ; 
*p = '\0'; 

더 나은 (안전) 당신이 복사 생성자에 사용한 솔루션 :

while (*q) 
    *p++ = *q++; 
*p = '\0'; 
+0

확인 됨 - 감사합니다. – Darel

+2

실제로, 첫 번째 예제에서'* p = '\ 0''을 제거하면 실제로 작동합니다. 'while (* p ++ = * q ++)'는 제로 문자를 복사 한 다음 중지합니다. (나는 그가 이렇게하는 것을 멈추고'string.h '에서 물건을 사용해야한다고 말하고 싶다. 예를 들어'memcpy'. C++ 사람은 C 사용자와 반대로' char *'를 사용하고'std :: string'을 제안하십시오.) – asveikau

+0

@asveikau : 당신은'* p = '\ 0''로 자리를 비 웠습니다. 그러나 이것이 운동이라면, 그는 수동으로해야합니다. (나는 왜 그가 std :: strlen()을 사용하는지에 대해 의문을 가질 수는 있지만, std :: strcpy()는 사용하지 않는다는 것에 동의한다.) – sbi

2
while (*p++ = *i++) ; // the last iteration is when i is one past the end 
// i is two past the end here -- you checked for a 0, found it, then incremented past it 
p--; //here you corrected for this 
while (*p++ = *q++) ;// the last iteration is when p and q are one past the end 
// p and q are two past the end here 
// but you didn't insert a correction here 
*p = '\0'; // this write is in unallocated memory 

사용하면 복사 생성자에 사용되는 것과 관용구 유사한

while (*i) *p++ = *i++; //in these loops, you only increment if *i was nonzero 
while (*q) *p++ = *q++; 
*p = '\0' 
+0

Valgrind는'* p = '\ 0'' 라인에서 에러를 포착합니다. –

1

힙을 휴지통으로 만드는 특정 오류를 가리키는 두 개의 대답이 이미 있습니다.

  • 경우 :이 가정하면 숙제 또는 (그렇지 않으면 우리는 자신의 문자열 클래스를 작성하기위한 당신 고함을 모두 할 것) 운동의 다른 형태이며, 당신을 위해 여기에 씹을 수있는 몇 가지 더있어 당신은 주석이 코드의 필요성을 느낄 수 있도록 더 표현을 만드는 것이 좋습니다.
    예를 들어 char* p = str; // new data 대신 char* new_data = str;을 쓸 수 있습니다.
    //do frgl 대신 코드 덩어리 다음에 do_frgl();을 쓸 수 있습니다. 함수가 인라인되면, 결과 코드에 차이는 없지만 코드 독자에게는 많은 차이가 있습니다.
  • 헤더를 포함한 모든 사람이 의 이름 공간 std의 모든 항목을 글로벌 네임 스페이스으로 덤프합니다. That's not a good idea at all. 전염병과 같은 머리글을 포함하지 않도록하십시오.
  • 생성자는 클래스 멤버를 이니셜 라이저 목록에 초기화해야합니다.
  • Str::Str(const char*) 생성자가 동일한 문자열에 대해 std::strlen()을 두 번 호출합니다. 이 글은 종료 응용 프로그램 당신이 모르는 반면에,, 라이브러리 코드를 필요에 따라
    응용 프로그램 코드가 최대한 빨리 해야한다, 최대한 빨리 해야한다 가능. 라이브러리 코드를 작성하고 있습니다.
  • size() 멤버 함수 적 음의 값을 반환 할 수 있을까요? 그렇지 않다면 왜 부호있는 정수인가?
  • 이 코드는 어떻게됩니까? Str s1, s2; s1=s2? 이것에 대해
  • 그리고 무엇 : Str str("abc"); std::cout<<str[1];

(.이 건너 오는 사람이 더 힌트를 생각할 수있는 경우이 확장 주시기)

+0

팁 주셔서 감사합니다. 숙제 자체가 아닙니다. 나는 내 직업에 능통 한 C + +를 배우고있다. 이것은 "Accelerated C++"문제 12-1에서 왔습니다. – Darel

+0

아, _Accelerated C++ _, 가파른 학습 곡선이 있지만 탁월한 선택입니다. 다음 C++ 도서의 최종 C++ 도서 목록을 확인하십시오. http://stackoverflow.com/questions/388242/. – sbi

3

는 이미 여기에 좋은 답변 무리가있다 하지만이 문제를 해결하기위한 도구로 Valgrind을 연결하는 것이 좋습니다. * nix 상자에 액세스 할 수 있다면 Valgrind 도구가 실제로 생명의 은인이 될 수 있습니다. 당신은 그것을 여기에 다른 답변 (라인 36) 근처 지적 선을 정확히 볼 수 있습니다

 
% g++ -g -o test test.cpp 
% valgrind ./test 
==2293== Memcheck, a memory error detector 
==2293== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. 
==2293== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info 
==2293== Command: ./test 
==2293== 
==2293== Invalid write of size 1 
==2293== at 0x8048A9A: Str::operator+=(Str const&) (test.cpp:36) 
==2293== by 0x8048882: main (test.cpp:82) 
==2293== Address 0x42bc0dc is 0 bytes after a block of size 12 alloc'd 
==2293== at 0x4025024: operator new[](unsigned int) (vg_replace_malloc.c:258) 
==2293== by 0x8048A35: Str::operator+=(Str const&) (test.cpp:26) 
==2293== by 0x8048882: main (test.cpp:82) 
==2293== 
helloworld! 
hello 
==2293== 
==2293== HEAP SUMMARY: 
==2293==  in use at exit: 0 bytes in 0 blocks 
==2293== total heap usage: 4 allocs, 4 frees, 31 bytes allocated 
==2293== 
==2293== All heap blocks were freed -- no leaks are possible 
==2293== 
==2293== For counts of detected and suppressed errors, rerun with: -v 
==2293== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 17 from 6) 
% 

:

그냥 여기 컴파일하고 그것을 통해 프로그램을 실행할 때 내가 가진 무엇을, 당신을 표시합니다.

+0

인상적 ... 그런 도구가 존재한다는 것을 몰랐습니다! 하지만 내 메인 워크 스테이션은 Windows 상자입니다. (여기서는 일부 검색을 수행했지만 Visual Studio의 경우 이와 같은 도구를 찾지 못했습니다 .Linux VM을 설정해야 할 수도 있습니다. 이러한 고급 디버깅 도구. – Darel

관련 문제