2014-07-07 2 views
1

동일한 질문을 검색하려고했지만 나에게 도움이되지 않았습니다. 프로그램을 실행할 때 "버퍼 오버런이 발생했습니다 ..."오류가 발생합니다.삭제 []가 포함 된 버퍼 오버런

| 생성자 :

Player(char* n) 
{ 
    length = strlen(n); 
    name = new char[length+1]; 

    for(unsigned int i(0); i < length; i++) 
     name[i] = n[i]; 

    name[length] = '\0'; 
} 

Destr : 나는 NULL 문자열을 종료했습니다과 범위를 벗어하지 않는

~Player(void) 
{ 
    delete [] name; 
} 

, 문제는 무엇인가?

+4

클래스가 [Rule of Three] (http://stackoverflow.com/questions/4172722)를 따르고 있습니까? 그렇지 않다면 동일한 버퍼를 두 번 삭제할 가능성이 있습니다.특히 포인터 - 저글링 기술을 연습하고 싶지 않으면'std :: string'을 사용하여 동적 메모리를 올바르게 관리하십시오. –

+2

문제를 일으키는 특정 코드가 무엇이라는 것을 어떻게 알 수 있습니까? – Jon

+0

관련 : [규칙 5] (http://stackoverflow.com/questions/4782757/rule-of-three-becomes-rule-of-five-with-c11) – Deduplicator

답변

1

게시 한 코드에는 명백한 오류가 없지만 원시 포인터를 저글링하여 동적 메모리를 관리하면 거의 필연적으로 이와 같은 오류가 발생할 수 있습니다.

Rule of Three에 따라 복사 생성자 및 복사 할당 연산자를 올바르게 구현 또는 삭제하지 않은 것일 수 있습니다. 이 경우 Player 객체를 복사하면 동일한 배열에 대한 포인터가있는 두 객체가 생깁니다. 둘 다 정의되지 않은 동작을 제공하여 해당 배열을 삭제하려고 시도합니다.

가장 간단한 해결책은 문자열 관리를 위해 설계된 클래스로 문자열을 관리하는 것입니다. std::stringname의 유형을 변경 한 다음 생성자는 간단하게 할 수 있습니다

explicit Player(std::string const & n) : name(n) {} 

같은 것을하고 소멸자를 선언 할 필요가 없습니다 (또는/생성자/대입 연산자를 복사, 이동) 전혀.

0

그래서 ... std::string을 사용하여 솔루션이 제공되었지만 멤버 변수를 그대로 유지하면서 다른 솔루션을 제공하겠습니다.

문제는 이것입니다. (1) 방법 Player& Player::operator=(const Player&)가 호출에서

Player p1("Bob"); // Okay 
Player p2("Annie"); // Okay 
p2 = p1; // Oops! (1) 
Player p3(p1); // Oops! (2) 

: 당신이 어딘가에이 코드가 있다고 가정. 당신이 제공하지 않았기 때문에, 컴파일러는 당신을 위해 하나를 생성합니다. 그럴 때 모든 멤버 변수를 복사 할 수 있다고 가정합니다. 이 경우 Player::namePlayer::length을 복사합니다. 그래서 우리는 p1.name == p2.name입니다. 이제 p2의 소멸자가 호출되면 p2.name이 가리키는 할당 된 메모리가 삭제됩니다. 그런 다음 소멸자 p1이 호출되면 과 동일한 메모리가 삭제됩니다 (p1.name == p2.name부터)! 그건 불법입니다.

이 문제를 해결하려면 할당 연산자를 직접 작성할 수 있습니다.

Player& Player::operator = (const Player& other) 
{ 
    // Are we the same object? 
    if (this == &other) return *this; 

    // Delete the memory. So call the destructor. 
    this->~Player(); 

    // Make room for the new name. 
    length = other.length; 
    name = new char[length + 1]; 

    // Copy it over. 
    for (unsigned int i = 0; i < length; ++i) name[i] = other.name[i]; 
    name[length] = '\0'; 

    // All done! 
    return *this; 
} 

(2)에서 동일한 문제가 발생합니다. 당신은 복사 생성자가 없으므로 컴파일러가 생성자를 생성합니다. 또한 모든 멤버 변수를 복사 할 수 있으므로 소멸자가 호출되면 동일한 메모리를 다시 삭제하려고 시도합니다. 당신이 불구하고 std::string를 사용해야 하루의 끝에서

Player::Player(const Player& other) 
{ 
    if (this == &other) return; 
    length = other.length; 
    name = new char[length + 1]; 
    for (unsigned int i = 0; i < length; ++i) name[i] = other.name[i]; 
} 

:이 문제를 해결하려면, 또한 복사 생성자를 작성합니다.

+0

감사합니다. 나는이 문제에 너무 가까웠다.하지만 10 분 전에이 책을 읽지 않았다.) 갑자기 'delete []'로 실수하지 않았다. 잘못된 질문으로 인해 유감이지만이 답변으로 내가 모르는 문제가 해결되었습니다. 다시 한 번 감사드립니다! – pushandpop

+0

복사 의미를 구현하는 가장 좋은 예는 아닙니다. 특히, 소멸자를 호출하지 마십시오. 이는 정의되지 않은 동작을 제공합니다 (비록 여기에서 벗어날지라도). 합리적인 예외 안전을 기원합니다. 메모리 할당이 실패하면 할당 대상에 매달린 포인터가 남습니다. 두 함수를 직접 코딩하는 것보다는 복사 생성자를 사용하여 안전한 할당을 위해 [copy-and-swap idiom] (http://stackoverflow.com/questions/3279543)을 고려하십시오. 새 객체를 초기화 할 때 생성자에서 동일한 객체를 확인할 필요가 없습니다. –