std :: unique_ptr 멤버와 함께 사용자 정의 삭제기를 사용하려면 어떻게합니까? 으로 함께 사용하고 싶다면 다음을

unique_ptr 멤버가있는 클래스가 있습니다.

class Foo {
private:
    std::unique_ptr<Bar> bar;
    ...
};

Bar는 create () 함수와 destroy () 함수가있는 타사 클래스입니다.

std::unique_ptr독립형 기능 으로 함께 사용하고 싶다면 다음을 수행 할 수 있습니다.

void foo() {
    std::unique_ptr<Bar, void(*)(Bar*)> bar(create(), [](Bar* b){ destroy(b); });
    ...
}

std::unique_ptr수업의 일원으로서 이것을 할 수있는 방법이 있습니까?



답변

그 가정 create하고 destroy다음 서명을 (영업 이익의 코드의 경우 것으로 보인다) 무료 기능입니다 :

Bar* create();
void destroy(Bar*);

Foo이런 식으로 수업을 쓸 수 있습니다

class Foo {

    std::unique_ptr<Bar, void(*)(Bar*)> ptr_;

    // ...

public:

    Foo() : ptr_(create(), destroy) { /* ... */ }

    // ...
};

destroy이미 삭제 도구 이므로 여기에 람다 또는 사용자 지정 삭제 도구를 작성할 필요가 없습니다 .


답변

C ++ 11 (G ++ 4.8.2에서 테스트)의 람다를 사용 하여이 작업을 깨끗하게 수행 할 수 있습니다.

이 재사용이 가능하면 typedef:

template<typename T>
using deleted_unique_ptr = std::unique_ptr<T,std::function<void(T*)>>;

당신은 쓸 수 있습니다:

deleted_unique_ptr<Foo> foo(new Foo(), [](Foo* f) { customdeleter(f); });

예를 들어 FILE*:

deleted_unique_ptr<FILE> file(
    fopen("file.txt", "r"),
    [](FILE* f) { fclose(f); });

이를 통해 try / catch 노이즈없이 RAII를 사용하여 예외 안전 클린업의 이점을 얻을 수 있습니다.


답변

삭제 클래스를 작성하면됩니다.

struct BarDeleter {
  void operator()(Bar* b) { destroy(b); }
};

의 템플릿 인수로 제공하십시오 unique_ptr. 여전히 생성자에서 unique_ptr을 초기화해야합니다.

class Foo {
  public:
    Foo() : bar(create()), ... { ... }

  private:
    std::unique_ptr<Bar, BarDeleter> bar;
    ...
};

내가 아는 한, 모든 인기있는 c ++ 라이브러리는 이것을 올바르게 구현합니다. 이후 BarDeleter 실제로 어떤 상태가없는, 그것은 어떤 공간을 점유 할 필요가 없습니다 unique_ptr.


답변

런타임에 삭제 프로그램을 변경할 수 없다면 사용자 지정 삭제 유형을 사용하는 것이 좋습니다. 예를 들어, Deleter가에 대한 함수 포인터를 사용하는 경우 sizeof(unique_ptr<T, fptr>) == 2 * sizeof(T*). 즉, 바이트의 절반unique_ptr 객체 이 낭비됩니다.

그러나 모든 기능을 래핑하기 위해 사용자 정의 삭제기를 작성하는 것은 귀찮습니다. 고맙게도 함수에 템플릿 형식을 작성할 수 있습니다.

C ++ 17부터 :

template <auto fn>
using deleter_from_fn = std::integral_constant<decltype(fn), fn>;

template <typename T, auto fn>
using my_unique_ptr = std::unique_ptr<T, deleter_from_fn<fn>>;

// usage:
my_unique_ptr<Bar, destroy> p{create()};

C ++ 17 이전 :

template <typename D, D fn>
using deleter_from_fn = std::integral_constant<D, fn>;

template <typename T, typename D, D fn>
using my_unique_ptr = std::unique_ptr<T, deleter_from_fn<D, fn>>;

// usage:
my_unique_ptr<Bar, decltype(destroy), destroy> p{create()};

답변

사용자 정의 삭제기를 사용하는 것이 코드 전체에서 언급해야하므로 최선의 방법은 아닙니다.
대신, 사용자 정의 유형이 포함되고 의미를 존중하는 한 네임 스페이스 수준 클래스에 전문화를 추가 할 수 있으므로 다음과 같이하십시오::std .

전문화하십시오 std::default_delete:

template <>
struct ::std::default_delete<Bar> {
    default_delete() = default;
    template <class U, class = std::enable_if_t<std::is_convertible<U*, Bar*>()>>
    constexpr default_delete(default_delete<U>) noexcept {}
    void operator()(Bar* p) const noexcept { destroy(p); }
};

그리고 아마도 할 수도 있습니다 std::make_unique():

template <>
inline ::std::unique_ptr<Bar> ::std::make_unique<Bar>() {
    auto p = create();
    if (!p) throw std::runtime_error("Could not `create()` a new `Bar`.");
    return { p };
}

답변

std::bind파괴 기능과 함께 간단히 사용할 수 있습니다 .

std::unique_ptr<Bar, std::function<void(Bar*)>> bar(create(), std::bind(&destroy,
    std::placeholders::_1));

그러나 물론 람다를 사용할 수도 있습니다.

std::unique_ptr<Bar, std::function<void(Bar*)>> ptr(create(), [](Bar* b){ destroy(b);});

답변