2011-11-24 2 views
7

아래 프로그램을 고려하십시오. 복잡한 경우에서 단순화되었습니다. Obj 클래스에서 가상 소멸자를 제거하지 않으면 이전에 할당 된 메모리를 삭제할 수 없습니다. 가상 소멸자가있는 경우에만 프로그램의 출력에서 ​​두 주소가 다른 이유를 이해할 수 없습니다. 가상 소멸자가 존재할 때 게재 위치 new []의 사용에있어 잘못된 점은 무엇입니까? do

// GCC 4.4 
#include <iostream> 

using namespace std; 

class Arena { 
public: 
    void* alloc(size_t s) { 
     char* p = new char[s]; 
     cout << "Allocated memory address starts at: " << (void*)p << '\n'; 
     return p; 
    } 

    void free(void* p) { 
     cout << "The memory to be deallocated starts at: " << p << '\n'; 
     delete [] static_cast<char*> (p); // the program fails here 
    } 
}; 

struct Obj { 
    void* operator new[](size_t s, Arena& a) { 
     return a.alloc(s); 
    } 

    virtual ~Obj() {} // if I remove this everything works as expected 

    void destroy(size_t n, Arena* a) { 
     for (size_t i = 0; i < n; i++) 
      this[n - i - 1].~Obj(); 
     if (a) 
      a->free(this); 
    } 
}; 


int main(int argc, char** argv) { 
    Arena a; 

    Obj* p = new(a) Obj[5](); 
    p->destroy(5, &a); 

    return 0; 
} 

내 구현 프로그램의 출력 :

에서

할당 된 메모리 어드레스는 시작 : 0x8895008 메모리는에서 시작을 해제 할 : 0x889500c

실행 실패 (종료 값 1)

어떤 프로그램이 필요한지 묻지 마십시오. 영형. 내가 말했듯이, Arena가 다양한 메모리 유형을위한 인터페이스 인보다 복잡한 경우에서부터옵니다. 이 예제에서 메모리는 힙에서 할당되고 할당이 해제됩니다.

+0

참고 * 일치하는 위치 배열이 새로운 표현에 예외를 throw하는 경우 삭제해야합니다. –

답변

5

this 당신은 크기 s는보다 큰 5 개 Obj 경우가 있음을 볼 수 있습니다 char* p = new char[s]; 줄에서 new에 의해 반환 된 포인터가 아니다. 차이 (sizeof (std::size_t)이어야 함)는 this에 포함 된 주소 바로 앞에 배열 길이 5를 포함하는 추가 메모리에 있습니다.

OK, 사양은 명확하게 :

http://sourcery.mentor.com/public/cxx-abi/abi.html#array-cookies

2.7 배열 연산자 새 쿠키

새로운 운영자가 새로운 배열을 만드는 데 사용하는 경우, 쿠키가 일반적으로 저장

기억 할당이 끝난 길이 (배열 요소의 수)에 의해 올바르게 할당 해제 할 수있다

배열 요소 타입 T 사소한 소멸자 (12.4 [class.dtor])과 일반 (배열) 해제 기능을 갖고 있으면 어떠한 쿠키가 필요하지 않다 (3.7.3.2 [basic.stc : 구체적

.dynamic.deallocation]) 함수는 두 개의 인수를 취하지 않습니다.

그래서, 소멸자의 가상 -ness 무엇 중요한 것은 소멸자가 쉽게 소멸자 앞에 키워드 virtual을 삭제하여, 확인 할 수있는 비 사소한 점이다, 무관 프로그램 충돌을 관찰하십시오. 당신이 "안전"하게하려는 경우, 오한 '답변에 따라

+0

예, 크기에 대해서는별로 신경 쓰지 않습니다. 나는이 포인터가 객체를 배치하기 위해 주어진 포인터와 일치하지 않는 이유에 대해 신경을 쓴다. – Martin

+0

@Martin, 왜냐하면'alloc()'은 배열의 길이를위한 추가 공간을 할당했고 배열 요소가 따라 왔기 때문입니다. 나는 가상 소멸자가 없다면 배열 길이를 저장하지 않는 이유를 지금은 모르지만 C++ ABI 스펙을 확인해야합니다. – chill

+0

어떤 사양입니까? 내 C++ 사양에는 쿠키에 대한 언급이 없습니다. –

0

: 당신이 * 할

#include <type_traits> 

a->free(this - (std::has_trivial_destructor<Obj>::value ? 1 : 0)); 
+1

정말로 (아마도 std :: size_t *)이 - (std :: has_trivial_destructor :: value? 1 : 0))','정말로 자유롭지는 않습니다.',하지만 그것은 엄밀히 말해서 UD이고 나는 확신합니다. 어떤 모호한 구석 및/또는 다른 컴파일러에서 중단됩니다;) – chill

관련 문제