2010-02-16 7 views
13

this one question asking the same thing이 발견되었지만 '새'부분 만 응답되었으므로 여기에 다시 나와 있습니다.delete 연산자가 정적 일 필요가있는 이유는 무엇입니까?

왜 삭제 연산자가 정적 일 필요가 있습니까? 여하튼 그것은 이해가되지 않는다. 새 연산자는 생성자가 가상 ​​일 수 없듯이 완벽한 연산자입니다. 새 연산자도 사용할 수 없습니다. 그러나 소멸자는 상속을 사용할 때 가상 클래스가 될 수 있으며 (다형성을 통해) 사용되는 객체를 기본 클래스로 파괴 할 수 있습니다.

나는 삭제 연산자가 호출 될 때 객체가 이미 파괴되었으므로 'this'가 존재하지 않는다는 것을 알고 있습니다. 그러나 가상 소멸자와 동일한 추론을 사용하여 삭제 연산자가 객체를 만든 새 연산자와 일치하도록하는 것이 여전히 의미가 있습니다. 하지만 아무것도 (가 정적입니다 그것은 알 수 없습니다 이후

은, 지금 우리가

A *ptr = new B(); 
delete ptr; // <-- fail 

A의 delete 연산자 (기본값) 할 경우

class A 
{ 
    public: 
    virtual ~A() {} 
}; 

class B : public A 
{ 
    public: 
    void* operator new (size_t sz); 
    void operator delete (void* ptr, size_t sz); 
}; 

을 무엇을 의미하는지라고 했어야이다 여기서 사소한 경우) 컴파일 타임에 delete-operator가 올바른 것입니다.

그러나 위의 코드를 사용하여 작은 테스트 프로그램을 만들었습니다 (새/삭제 연산자에서 malloc/free 및 delete에서 print 문 만). g ++를 사용하여 컴파일했습니다. 그것을 실행하면 예기치 않게 B의 삭제 연산자에서 출력이 생성됩니다.

내 (실제) 질문입니다. 삭제 연산자에 암시 적 '가상'이 있습니까? 이 포인터가없는 의미에서만 정적입니까? 아니면 그냥 g ++ 기능입니까?

C++ 사양을 살펴보기 시작했지만, 나는 그것에 압도 당해서 도움이된다고 인정해야합니다.

답변

16

언어 규칙의 대답은 실제로 12.5 [class.free]입니다.

포인터를 통해 기본 클래스에 삭제하려는 경우 소멸자가 가상이어야하거나 정의되지 않은 동작이 발생합니다. 그렇지 않은 경우 구현시 삭제할 객체의 동적 유형을 결정해야합니다.

12.5/4는 delete은 다음 :: 접두사되지 않을 때 해제 기능이 동적 유형의 가상 소멸자의 맥락에서 delete를 찾고에 의해 결정되는 것을 말한다. operator delete은 항상 static 멤버 함수 임에도 불구하고 가상 같은 조회를 보장합니다.

원시 할당 및 할당 취소는 개념적으로 개체의 유효 기간 외가되므로 할당 취소 기능을 호출 할 때까지 더 이상 가상 검색 메커니즘을 제공 할 개체가 없지만 조회 규칙에 따라 operator delete에는 동적 가상 - 라이트!) 조회 메커니즘. 즉, 원래 개체의 동적 유형으로 터치를 잃지 않고 연산자 삭제가 현명하게 static이 될 수 있습니다.

+0

우수, 감사합니다! 나는 3.7.3에서 주변을 뒤적 거리고 있었다. ... – falstro

+3

또한 5.3.5와 3.7.3과 12.5에도 관련성이있다. 참조 작업으로 청구되었지만 실제로는 다른 섹션에서 찾고있는 것과 관련이있는 작은 단락이 있는지를 알지 못한다면 실제로 덮어 씌울 필요가 있습니다. 찾고. –

1

delete 연산자는 메모리 만 할당 해제하고 대부분의 파생 클래스 객체에 대해 전체 작업을 할당 취소합니다. 한 동작에서는연산자와 완전히 똑같은 방식으로 가장 많이 파생 된 클래스 객체에 할당됩니다. 클래스의 객체는 인수로 new Class 구조로 전달됩니다.

delete ptr; 할 때 delete 연산자는 항상 삭제되는 개체의 실제 가장 파생 클래스에 대해 한 번만 호출되며 가상 소멸자가있는 경우 vtable에서 어떤 클래스의 데이터가 추론되는지를 확인합니다. 현재 또는 가상 소멸자가없는 경우 포인터 유형. 그것이 delete 연산자에 대한 암시 적 가상 효과가없는 이유입니다. 모든 가상 효과는 소멸자 호출 시점에서 끝납니다.

+0

@roe : 가장 파생 된 클래스 연산자 delete는 파생 된 연산자 new가 호출 된 것과 같은 방식으로 호출됩니다. 따라서 서로 다른 뱅크를 가지고 있다면 서로 다른 클래스의 객체를 다른 뱅크에서 할당받을 수 있지만 전체 객체로만 하위 객체가 하나의 뱅크에 있고 객체의 파생 클래스 부분이 다른 객체에있는 것은 결코 발생하지 않습니다. – sharptooth

+0

실제 연산자가 어떤 클래스에서 추론되는지 (예 : 가상 테이블을 찾거나 작동하는 경우) 연산자에 암시적인 가상의 느낌이들 정도입니까? B에서 파생 된 클래스 C가 있다고 가정하면'A ​​* ptr = new C; delete ptr;'은 여전히 ​​B의 delete 연산자를 호출합니다. 이것은 꽤 가상적인 것처럼 들립니다. 스팸성 댓글에 대해 유감스럽게 생각합니다. 나는 단지 내 머리를 감싸려고 노력하고 있습니다. – falstro

+0

@roe : 삭제 및 새 연산자가 상속됩니다. 클래스 B에서 클래스를 오버로드 했으므로 C 클래스도이 클래스를 사용합니다. 여기 좋은 차트를보십시오 : http://msdn.microsoft.com/en-us/library/c5at8eya.aspx – sharptooth

관련 문제