developer tip

shared_ptr 매직 :)

optionbox 2020. 10. 8. 07:55
반응형

shared_ptr 매직 :)


Mr. Lidström과 저는 다툼을했습니다. :)

Lidström의 주장은 구조 shared_ptr<Base> p(new Derived);가 Base에 가상 소멸자를 필요로하지 않는다는 것입니다 .

Armen Tsirunyan : "정말? shared_ptr이 올바르게 정리 될까요?이 경우 어떻게 그 효과를 구현할 수 있는지 보여 주시겠습니까?"

Daniel Lidström : " shared_ptr 는 자체 소멸자를 사용하여 Concrete 인스턴스를 삭제합니다. 이것은 C ++ 커뮤니티 내에서 RAII로 알려져 있습니다. 제 조언은 RAII에 대해 배울 수있는 모든 것을 배우는 것입니다. 사용하면 C ++ 코딩이 훨씬 쉬워 질 것입니다. 모든 상황에서 RAII. "

Armen Tsirunyan : "RAII에 대해 알고 있습니다. 또한 pn이 0에 도달하면 shared_ptr 소멸자가 저장된 px를 삭제할 수 있다는 것도 알고 있습니다. 그러나 px 에에 대한 정적 형식 포인터 Base와에 대한 동적 형식 포인터 가있는 경우 가상 소멸자가 Derived없는 한 Base이것은 정의되지 않은 동작이 발생합니다. 내가 틀렸다면 수정하십시오. "

Daniel Lidström : " shared_ptr 은 정적 유형이 Concrete라는 것을 알고 있습니다. 생성자에 전달했기 때문에 이것을 알고 있습니다! 약간 마술처럼 보이지만 설계 상 매우 훌륭하다고 확신 할 수 있습니다."

그래서 우리를 판단하십시오. 가상 소멸자를 갖기 위해 다형성 클래스를 요구하지 않고 shared_ptr 을 구현하는 것이 어떻게 가능 합니까? 미리 감사드립니다


예, 그런 방식으로 shared_ptr을 구현하는 것이 가능합니다. Boost는 그렇고 C ++ 11 표준도이 동작을 요구합니다. 추가 된 유연성으로 shared_ptr은 단순한 참조 카운터 이상을 관리합니다. 소위 삭제자는 일반적으로 참조 카운터도 포함하는 동일한 메모리 블록에 배치됩니다. 그러나 재미있는 부분은이 삭제 자의 유형이 shared_ptr 유형의 일부가 아니라는 것입니다. 이를 "타입 삭제"라고하며 기본적으로 실제 펑터의 유형을 숨기기 위해 "다형성 함수"boost :: function 또는 std :: function을 구현하는 데 사용되는 것과 동일한 기술입니다. 예제가 작동하도록하려면 템플릿 생성자가 필요합니다.

template<class T>
class shared_ptr
{
public:
   ...
   template<class Y>
   explicit shared_ptr(Y* p);
   ...
};

따라서 이것을 Base 및 Derived 클래스와 함께 사용하면 ...

class Base {};
class Derived : public Base {};

int main() {
   shared_ptr<Base> sp (new Derived);
}

... Y = Derived 인 템플릿 생성자는 shared_ptr 객체를 생성하는 데 사용됩니다. 따라서 생성자는 적절한 삭제 자 개체와 참조 카운터를 만들고이 제어 블록에 대한 포인터를 데이터 멤버로 저장할 수 있습니다. 참조 카운터가 0에 도달하면 이전에 생성되고 파생 인식 삭제 기가 개체를 처리하는 데 사용됩니다.

C ++ 11 표준에는이 생성자 (20.7.2.2.1)에 대해 다음과 같은 내용이 있습니다.

필요 : p 로 변환 할 수 있어야합니다 T*. Y완전한 유형이어야합니다. 표현 delete p은 잘 형성되어야하고 잘 정의 된 행동을 가져야하며 예외를 던지지 않아야합니다.

효과 : 포인터 소유shared_ptr개체 를 생성 합니다 .p

그리고 소멸자의 경우 (20.7.2.2.2) :

효과 :*this비어 있거나 다른 shared_ptr인스턴스 ( use_count() > 1) 와 소유권을 공유하는 경우 부작용이 없습니다. 그렇지 않으면, *this객체 소유 p하고 Deleter가를 d, d(p)이라고합니다. 그렇지 않은 경우는 *this포인터를 소유 p하고, delete p라고합니다.

(굵은 글꼴을 사용한 강조는 내 것입니다).


shared_ptr을 생성 할 때 그것은 저장 Deleter가의 자체 내부 개체. 이 개체는 shared_ptr이 지적 된 리소스를 해제하려고 할 때 호출됩니다. 생성 시점에서 리소스를 파괴하는 방법을 알고 있으므로 불완전한 유형으로 shared_ptr을 사용할 수 있습니다. shared_ptr을 만든 사람은 거기에 올바른 삭제자를 저장했습니다.

예를 들어 사용자 지정 삭제자를 만들 수 있습니다.

void DeleteDerived(Derived* d) { delete d; } // EDIT: no conversion needed.

shared_ptr<Base> p(new Derived, DeleteDerived);

p는 뾰족한 객체를 파괴하기 위해 DeleteDerived를 호출합니다. 구현은이를 자동으로 수행합니다.


간단히,

shared_ptr Base의 소멸자가 아닌 지정된 객체의 소멸자를 항상 사용하는 생성자에 의해 생성되는 특수 삭제 기능을 사용합니다. 이것은 템플릿 메타 프로그래밍에서 약간의 작업이지만 작동합니다.

그런 것

template<typename SomeType>
shared_ptr(SomeType *p)
{
   this->destroyer = destroyer_function<SomeType>(p);
   ...
}

참고 URL : https://stackoverflow.com/questions/3899790/shared-ptr-magic

반응형