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);});