IT story

삭제가 허용됩니까?

hot-time 2020. 4. 22. 08:14
반응형

삭제가 허용됩니까?


delete this;delete-statement가 클래스의 해당 인스턴스에서 실행될 마지막 명령문 인 경우 허용 됩니까? 물론 - this포인터가 나타내는 객체 new생성 된 것이 확실합니다 .

나는 이것에 대해 생각하고있다 :

void SomeModule::doStuff()
{
    // in the controller, "this" object of SomeModule is the "current module"
    // now, if I want to switch over to a new Module, eg:

    controller->setWorkingModule(new OtherModule());

    // since the new "OtherModule" object will take the lead, 
    // I want to get rid of this "SomeModule" object:

    delete this;
}

내가 할 수 있습니까?


C ++ FAQ Lite에는 특별히이 항목이 있습니다.

나는이 인용문을 잘 요약한다고 생각합니다.

조심하는 한 개체가 자살하는 것이 좋습니다 (삭제).


예, delete this;객체가 동적으로 할당되고 객체가 파괴 된 후에는 절대로 객체를 사용하려고 시도하지 않는 한 결과를 정의했습니다. 수년에 걸쳐 delete this;다른 포인터를 삭제하는 대신 표준에 대해 구체적으로 말하는 것에 대해 많은 질문이 제기되었습니다 . 그것에 대한 대답은 상당히 짧고 간단합니다. 그것은 단지 말한다 delete'의 피연산자는 객체 또는 객체의 배열에 대한 포인터를 지정하는 식이어야합니다. 메모리를 해제하기 위해 호출하는 할당 해제 기능을 알아내는 방법과 같은 것들에 대해 상당히 자세히 설명하지만 delete(§ [expr.delete]) 의 전체 섹션에서 delete this;특별히 언급하지는 않습니다 . destrucors 섹션에 언급되어 있습니다delete this 한 곳에서 (§ [class.dtor] / 13) :

가상 소멸자의 정의 시점 (암시 적 정의 (15.8) 포함)에서 비 배열 할당 해제 함수는 표현식이 소멸자 클래스의 비가 상 소멸자에 나타나는 것을 삭제하는 것처럼 결정됩니다 (8.3.5 참조). ).

그것은 표준 delete this;이 유효 하다고 생각하는 아이디어를지지하는 경향이 있습니다. 만약 그것이 유효하지 않다면, 그 유형은 의미가 없습니다. 그것이 delete this;내가 아는 한, 표준이 언급 한 유일한 곳 입니다.

어쨌든, 일부 delete this는 불쾌한 해킹을 고려 하고 들어야 할 사람은 피해야한다고 말합니다. 일반적으로 인용되는 문제 중 하나는 클래스의 객체가 동적으로 만 할당되는 것이 어렵다는 것입니다. 다른 사람들은 그것을 완벽하게 합리적인 관용구로 생각하고 항상 사용합니다. 개인적으로 저는 중간에 있습니다. 거의 사용하지 않지만, 업무에 적합한 도구 인 것 같으면 주저하지 마십시오.

이 기술을 사용하는 첫 번째 시간은 거의 전적으로 자신의 수명을 가진 개체를 사용하는 것입니다. James Kanze가 인용 한 한 가지 사례는 전화 회사에서 근무한 청구 / 추적 시스템입니다. 전화를 걸 때 무언가가이를 기록하고 phone_call객체를 만듭니다 . 이 시점부터 phone_call객체는 전화 통화의 세부 정보를 처리합니다 (전화를 걸 때 연결, 전화를 걸 때 말하는 데이터베이스에 항목 추가, 전화 회의를하는 경우 더 많은 사람을 연결할 수 있음). 마지막으로 전화를 건 사람이 전화를 끊으면 해당 phone_call객체는 최종 부기 작업을 수행합니다 (예 : 전화를 끊은 시간을 말하도록 데이터베이스에 항목을 추가하여 전화 시간을 계산할 수 있음). 평생phone_call객체는 첫 번째 사람이 전화를 시작한 시간과 마지막 사람이 전화를 떠날 때를 기반으로합니다. 시스템의 나머지 부분에서 볼 때 기본적으로 완전히 임의적이므로 코드의 어휘 범위에 연결할 수 없습니다 또는 그 순서에 따라

이러한 종류의 코딩이 얼마나 신뢰할 수 있는지에 관심이있는 사람은 유럽에서 거의 모든 지역을 통해 전화를 걸면 코드로 (적어도 부분적으로) 처리 될 가능성이 큽니다. 정확히이 작업을 수행합니다.


그것이 당신을 두려워한다면, 완전히 합법적 인 해킹이 있습니다.

void myclass::delete_me()
{
    std::unique_ptr<myclass> bye_bye(this);
}

나는 delete this관용적 인 C ++ 이라고 생각 하며 이것을 호기심으로 만 제시합니다.

이 구문이 실제로 유용한 경우가 있습니다. 객체에서 멤버 데이터가 필요한 예외를 throw 한 후 객체를 삭제할 수 있습니다. 던지기가 끝날 때까지 개체는 계속 유효합니다.

void myclass::throw_error()
{
    std::unique_ptr<myclass> bye_bye(this);
    throw std::runtime_exception(this->error_msg);
}

참고 : C ++ 11보다 오래된 컴파일러를 사용하는 경우 std::auto_ptr대신 대신 사용할 수 있습니다 std::unique_ptr.


C ++가 설계된 이유 중 하나는 코드를 쉽게 재사용 할 수 있도록하기위한 것입니다. 일반적으로 C ++은 클래스가 힙, 배열 또는 스택에서 인스턴스화되는지 여부에 관계없이 작동하도록 작성해야합니다. "삭제"는 단일 인스턴스가 힙에 정의 된 경우에만 작동하기 때문에 매우 나쁜 코딩 방법입니다. 그리고 대부분의 개발자가 힙을 정리하기 위해 일반적으로 사용하는 또 다른 delete 문이 더 나지 않았습니다. 이렇게하면 향후 유지 관리 프로그래머가 delete 문을 추가하여 잘못 인식 된 메모리 누수를 치료할 수 없다고 가정합니다.

현재 계획이 힙에 단일 인스턴스 만 할당한다는 것을 미리 알고 있다고해도, 운이 좋은 개발자가 나중에 와서 스택에 인스턴스를 작성하기로 결정하면 어떻게됩니까? 또는 클래스의 특정 부분을 잘라서 스택에 사용하려는 새 클래스에 붙여 넣으면 어떻게됩니까? 코드가 "삭제"에 도달하면 코드가 사라지고 삭제되지만 개체가 범위를 벗어나면 소멸자를 호출합니다. 그러면 소멸자가 다시 삭제하려고 시도한 후 호스를칩니다. 과거에는 이와 같은 작업을 수행하면 프로그램뿐만 아니라 운영 체제와 컴퓨터를 재부팅해야합니다. 어쨌든 이것은 권장되지 않으며 거의 ​​항상 피해야합니다. 필사적이고 진지하게 회개해야했는데


허용되지만 (그 후에 객체를 사용하지 마십시오) 실제로는 그러한 코드를 작성하지 않습니다. 나는 그 생각 delete this이라고 만 기능에 나타납니다 release또는 Release과 외모처럼 : void release() { ref--; if (ref<1) delete this; }.


COM (구성 요소 개체 모델)에서 delete this구성은 Release필요한 개체를 해제 할 때마다 호출 되는 메서드 의 일부일 수 있습니다 .

void IMyInterface::Release()
{
    --instanceCount;
    if(instanceCount == 0)
        delete this;
}

이것은 참조 횟수 개체의 핵심 관용구입니다.

참조 카운팅은 강력한 결정 론적 가비지 콜렉션의 형태로, 객체가 '스마트 한'포인터 등에 의존하는 대신 객체가 자신의 수명을 관리하도록합니다. 기본 개체는 "참조"스마트 포인터를 통해서만 액세스되며, 포인터는 실제 개체에서 멤버 정수 (참조 수)를 증가시키고 감소시킵니다.

마지막 참조가 스택에서 떨어지거나 삭제되면 참조 카운트가 0이됩니다. 그러면 객체의 기본 동작은 가비지 수집에 대한 "삭제"호출입니다. 작성한 라이브러리는 기본 클래스에서 보호 된 가상 "CountIsZero"호출을 제공하므로 캐싱과 같은 경우이 동작을 재정의 할 수 있습니다.

이것을 안전하게 만드는 열쇠는 사용자가 해당 객체의 생성자에 액세스하는 것을 허용하지 않고 (보호하도록) 대신 "정적 참조 CreateT (...)"와 같은 일부 정적 멤버를 FACTORY로 호출하게하는 것입니다. 그렇게하면 항상 일반 "새"로 작성되었으며 사용할 수있는 원시 포인터가 없다는 것을 알고 있으므로 "삭제"가 터지지 않습니다.


그렇게 할 수 있습니다. 그러나 이에 할당 할 수 없습니다. 따라서 "내가보기를 바꾸고 싶다"고 말한 이유는 매우 의심 스럽다. 내 의견으로는 더 나은 방법은 뷰를 유지하는 객체가 해당 뷰를 대체하는 것입니다.

물론, 당신은 RAII 객체를 사용하고 있으므로 실제로 delete를 전혀 호출 할 필요가 없습니다 ... 맞습니까?


이것은 오래되고 대답 된 질문이지만 @Alexandre는 "왜 이것을 원할까요?"라고 물었고, 오늘 오후에 고려할 사용법의 예를 제공 할 수 있다고 생각했습니다.

레거시 코드. 알몸 포인터 Obj * obj를 삭제 obj와 함께 사용합니다.

불행히도 때로는 종종 개체를 더 오래 살리기 위해 필요합니다.

참조 카운트 스마트 포인터로 만드는 것을 고려하고 있습니다. 그러나 모든 곳 에서 사용한다면 변경해야 할 코드 많이ref_cnt_ptr<Obj> 있습니다. 그리고 벌거 벗은 Obj *와 ref_cnt_ptr을 혼합하면 Obj *가 아직 살아 있더라도 마지막 ref_cnt_ptr이 사라질 때 내재적으로 삭제 된 객체를 얻을 수 있습니다.

그래서 explicit_delete_ref_cnt_ptr을 만드는 것에 대해 생각하고 있습니다. 즉, 삭제는 명시적인 삭제 루틴에서만 수행되는 참조 카운트 포인터입니다. 기존 코드가 객체의 수명을 알고있는 곳과 객체를 더 오래 살리는 새로운 코드에서 사용하십시오.

explicit_delete_ref_cnt_ptr이 참조 될 때 참조 카운트를 늘리거나 줄입니다.

그러나 explicit_delete_ref_cnt_ptr 소멸자에서 참조 횟수가 0으로 표시되면 해제되지 않습니다.

명시적인 삭제와 유사한 작업에서 참조 횟수가 0 인 경우에만 해제됩니다. 예를 들면 다음과 같습니다.

template<typename T> class explicit_delete_ref_cnt_ptr { 
 private: 
   T* ptr;
   int rc;
   ...
 public: 
   void delete_if_rc0() {
      if( this->ptr ) {
        this->rc--;
        if( this->rc == 0 ) {
           delete this->ptr;
        }
        this->ptr = 0;
      }
    }
 };

좋아, 그런 것. 참조 카운트 포인터 유형이 rc'ed ptr 소멸자에서 가리키는 객체를 자동으로 삭제하지 않는 것은 조금 특이합니다. 그러나 이것이 벌거 벗은 포인터와 rc'ed 포인터를 조금 더 안전하게 혼합하는 것처럼 보입니다.

그러나 지금까지 이것을 삭제할 필요는 없습니다.

그러나 그것은 나에게 일어났다 : 포인트가 가리키는 객체가 참조 카운트되고 있음을 알고 있다면, 예를 들어 카운트가 객체 내부 (또는 다른 테이블)에있는 경우, delete_if_rc0 루틴은 (스마트) 포인터가 아닌 pointee 객체.

class Pointee { 
 private: 
   int rc;
   ...
 public: 
   void delete_if_rc0() {
        this->rc--;
        if( this->rc == 0 ) {
           delete this;
        }
      }
    }
 };

실제로, 그것은 멤버 메소드 일 필요는 없지만 무료 기능이 될 수 있습니다.

map<void*,int> keepalive_map;
template<typename T>
void delete_if_rc0(T*ptr) {
        void* tptr = (void*)ptr;
        if( keepalive_map[tptr] == 1 ) {
           delete ptr;
        }
};

(BTW, 코드가 옳지 않다는 것을 알고 있습니다. 세부 사항을 모두 추가하면 코드가 읽기 어려워 지므로 코드를 그대로 둡니다.)


객체가 힙에있는 한이 방법은 유효합니다. 객체는 힙 전용이어야합니다. 그렇게하는 유일한 방법은 소멸자를 보호하는 것입니다.이 방법으로 delete는 class에서만 호출 될 수 있으므로 삭제를 보장하는 메소드가 필요합니다.

참고 URL : https://stackoverflow.com/questions/3150942/is-delete-this-allowed

반응형