2015-01-02 4 views
3

나는 아직도 shared_ptr과 함께 커스텀 deleter를 사용하는 적절한 방법에 대해서 다소 혼란 스럽다. 나는 자원 할당의 트랙을 유지하는 ResourceManager에 클래스가 있고, 나는 릴리스 방법은 개인 만들어 사용하는 자원의 자동 릴리스를 지원하고, ResourceHolder 반환 방법을 할당하기 위해 인터페이스를 수정 :사용자 정의 shared_ptr deleter를 올바르게 사용하는 방법은 무엇입니까?

// ResourceManager.cpp: 
public: 
    ResourceHolder<Resource> Allocate(args); 

private: 
    void Release(Resource*); 

그리고 ResourceHolder 클래스 I을 다음과 같이 구현 : 내 정리 방법에

// ResourceHolder.h 
template <typename T> 
class ResourceHolder 
{ 
public: 
    ResourceHolder(
     _In_ T* resource, 
     _In_ const std::function<void(T*)>& cleanupFunction) 
     : _cleanupFunction(cleanupFunction) 
     , _resource(resource, [&](T* resource) 
     { 
      cleanup(resource); 
     }) // Uses a custom deleter to release the resource. 
    { 
    } 

private: 
    std::function<void(T*)> _cleanupFunction; 
    std::shared_ptr<T> _resource; 
}; 

// ResourceManager::Allocate() 
... 
return ResourceHolder<Resource>(new Resource(),[this](Resource* r) { Release(r); }); 
  1. 을, 나는 T를 삭제해야합니까? 항상 그것을하는 것이 안전합니까?

    if (nullptr != T) delete T; 
    
  2. cleanup()이 예외를 throw 할 수 있다면 어떻게됩니까? 어떤 상황에서 범위를 벗어나게하거나, 항상 예방해야합니까?

  3. 내 ResourceManager에는 사용중인 추적 라이브러리에 대한 종속성이 없으므로 호출자가 해당 생성자를 통해 제공 할 수있는 콜백을 선택했으며 릴리스 방법에서 호출되는 콜백을 선택했습니다.

    void Release(Resource* r) 
    { 
        shared_ptr<std::Exception> exc = nullptr; 
        try 
        { 
         // Do cleanup. 
        } 
        catch(Exception* ex) 
        { 
         exc.reset(ex); 
        } 
    
        if (nullptr != r) delete r; 
    
        // Is it now safe to throw? 
        if (nullptr != m_callback) 
         m_callback(args, exc); 
    } 
    
    void Callback(args, shared_ptr<std::Exception> ex) 
    { 
        // Emit telemetry, including exception information. 
    
        // If throwing here is ok, what is the correct way to throw exception here? 
        if (nullptr != ex) 
        { 
         throw ex; 
        } 
    } 
    

이 사운드 디자인 접근 방식 : 그래서 내 릴리스는 다음과 같이 보이는?

+0

_ "건전한 설계 방법입니까?"_ - 아니요. '해제'는 객체 파괴와 관련하여 호출 할 수 있습니다. 예외가 이미 진행 중이므로이 단계에서 발생하는 예외가 주요 문제 일 수 있습니다. –

+0

그러나 try catch 블록의 모든 것을 래핑하고 notback()을 콜백으로 만드는 것은 괜찮을까요? –

답변

1

내 정리 방법에서 T를 삭제해야합니까? 항상 그것을하는 것이 안전합니까? 포인터가 new와 인스턴스 객체를 참조 경우

당신은 그렇지 않으면 메모리 누수 및 정의되지 않은 동작으로 끝낼 delete를 호출해야합니다.

cleanup()이 예외를 throw 할 수 있다면 어떻게됩니까? 어떤 상황에서 범위를 벗어나게하거나, 항상 예방해야합니까?

그렇지 않아야하며 그렇게하지 않도록 노력해야합니다. 그러나 클린업 코드 예외를 던지면이를 잡아서 적절히 처리해야하고 먹습니다. 그 이유는 소멸자의 컨텍스트에서 사용자 정의 deleter를 호출 할 수 있으며 예외가 이미 전파되는 동안 소멸자가 호출 될 가능성이 있기 때문입니다. 예외가 이미 진행 중이고 catch되지 않은 예외가 발생하면 응용 프로그램이 종료됩니다. 즉, 사용자 정의 삭제 자 및 정리 코드를 소멸자 인 것처럼 취급하고 예외 처리와 관련된 규칙 및 지침을 따르십시오.

Effective C++ 항목 # 8 -

소멸자가 예외를 방출해서는 안 떠나 소멸자에서 예외를 방지합니다. 소멸자에서 호출 된 함수가 발생하는 경우 소멸자는 예외를 잡아서 프로그램을 삼켜 버리거나 프로그램을 종료해야합니다.

§ 15.1/7 C++ 표준 [제외.예외 처리 메커니즘은, 식의 평가를 완료 한 후 발생 할 수 있지만 예외가 잡힌 전에 예외를 통해 종료 함수를 호출하면, std::terminate가 호출]

에게 던져.

-이 사운드 디자인 접근

인가?

현재 예외 처리 방법을 제외하고는 아무 문제가 없습니다. 실제로 필요한 유일한 변경 사항은 콜백을 호출하는 방법과 콜백이 전달 된 예외를 처리하는 방법입니다. 변경 후의 결과 코드는 다음과 같습니다.