2016-10-10 3 views
6

일반적인 C++ 디자인에서 대부분의 객체는 delete 문, free 함수 또는 free과 같은 라이브러리 특정 함수로 삭제할 수 있습니다. 이러한 객체의 경우 unique_ptrDeleter 구현은 빈 기본 클래스 최적화를 통해 제거되는 상태없는 객체가 될 수 있습니다. 그러나 일부 라이브러리는 라이브러리에서 오브젝트를 삭제하기 위해 다른 오브젝트 (함수 포인터 또는 기타 컨텍스트를 포함 할 수 있음)를 사용해야합니다.unique_ptr deleter overhead

typedef struct lib_object lib_object; 

struct lib_api { 
    lib_object (*createInstance)(); 
    void (*freeInstance)(lib_object *o); 
}; 

하나 맞춤 Deleter에서 데이터 부재로서의 lib_api 포인터를 저장함으로써 unique_ptr이 포장 할 수도 있지만 필요 lib_object 다중 인스턴스를 관리 할 경우, 예를 들어 컨테이너에서 객체 추적의 메모리 오버 헤드를 두 배로 늘릴 수 있습니다. 이 라이브러리를 다룰 때 어떤 종류의 패턴을 사용하여 RAII 원칙을 유지하면서 메모리를 효율적으로 사용할 수 있습니까?

+0

'lib_api *'를 deleter 클래스의 정적 멤버로 만들 수 있습니까? – Brian

+0

컨테이너 클래스의 사용자 정의 파생 클래스에'freeInstance'를 저장하고 컨테이너에'lib_object *'가 포함되어야한다고 생각합니다.파생 클래스에서 모든 요소에 대해'freeInstance'를 호출하는 소멸자를 구현해야합니다. – Franck

답변

5

lib_api 개체가 하나 뿐인 경우에는 삭제 자에게 정적 포인터를 가져다 놓을 수 있습니다.

두 개 이상의 lib_api 개체가있을 수는 있지만 삭제 자에게 포인터를 저장할 수밖에 없습니다.

+0

이것에 대해 생각해 보았는데 전역 변수가 유일한 유용한 해결책 인 것 같습니다. – 68ejxfcj5669

2

이러한 개체에 대한 사용자 지정 삭제 프로그램 템플릿을 사용합니다.

template<typename T, T Function> 
struct function_deleter 
{ 
    template<typename U> 
    auto operator()(U&& u) const noexcept(noexcept(Function(std::forward<U>(u)))) 
    { 
     return Function(std::forward<U>(u)); 
    } 
}; 

는 당신은 당신 Deleter가 호출 free을 사용할 수 있습니다 :

unique_ptr<int, function_deleter<void(*)(void*), &free>> uniq; 

그리고 그 크기는 여전히 하나의 포인터와 같다.

template<auto Function> 
struct function_deleter 
{ 
    template<typename U> 
    auto operator()(U&& u) const noexcept(noexcept(Function(std::forward<U>(u)))) 
    { 
     return Function(std::forward<U>(u)); 
    } 
}; 

unique_ptr<int, function_deleter<&call_free>> uniq; 

live demo

: live demo

는 당신이 코드를 단순화, 비 형 템플릿 매개 변수에 대한 auto을 사용할 수 있습니다 C++ (17) 가자 이 경우, 당신의 경우에는 unique_ptr<pair<lib_object, lib_api>>을이 구조를 지원하는 static deleter로 유지할 것입니다.

using lib_pair = pair<lib_object, lib_api>; 

void lib_free(lib_pair* p){ 
    p->second.freeInstance(p->first); 
    delete p; 
} 


using unique_lib_ptr = unique_ptr<lib_pair, function_deleter<void(*)(lib_pair*), &lib_free>> 

이것은 캐시가 많이 걸리는 것처럼 보일 수 있지만 귀하의 것일 수 있습니다.

0

더 우아한 해결책이 존재해야하지만 그것은 unique_ptr를 사용하지 않는

template <class ContainerType> 
class TObjectContainer : public ContainerType { 
    public: 
    TObjectContainer() = default; 
    TObjectContainer(const TObjectContainer&); // should call createCopy 
    TObjectContainer(TObjectContainer&&) = default; 
    ~TObjectContainer() 
    { for (lib_object* element : *this) 
     (*freeInstance)(element); 
    } 

    private: 
    void (*freeInstance)(lib_object *o); 
}; 

typedef TObjectContainer<std::vector<lib_object*>> ObjectVector; 

처럼 작성할 수 있지만 일을 기본적으로해야합니다.

clear과 같은 제거 방법을 과부하하면 freeInstance 또는 pop_back으로 전화하여 원래 std::unique_ptr을 돌려 보낼 수 있습니다.