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
객체 바이트의 절반 이 낭비됩니다.
Writing a custom deleter to wrap every function is a bother, though. Thankfully, we can write a type templated on the function:
Since 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()};
Prior to 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()};
You can simply use std::bind
with a your destroy function.
std::unique_ptr<Bar, std::function<void(Bar*)>> bar(create(), std::bind(&destroy,
std::placeholders::_1));
But of course you can also use a lambda.
std::unique_ptr<Bar, std::function<void(Bar*)>> ptr(create(), [](Bar* b){ destroy(b);});
You know, using a custom deleter isn't the best way to go, as you will have to mention it all over your code.
Instead, as you are allowed to add specializations to namespace-level classes in ::std
as long as custom types are involved and you respect the semantics, do that:
Specialize 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); }
};
And maybe also do 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 };
}
'IT story' 카테고리의 다른 글
MySQL에서 일괄 삽입을 수행하는 방법 (0) | 2020.07.11 |
---|---|
ASP.NET MVC 조건부 유효성 검사 (0) | 2020.07.11 |
패턴 앞에 줄 바꿈을 삽입하는 방법은 무엇입니까? (0) | 2020.07.11 |
Flask 앱에 정의 된 모든 경로 목록 가져 오기 (0) | 2020.07.11 |
파이썬에서 지수 및 로그 곡선 피팅을 수행하는 방법은 무엇입니까? (0) | 2020.07.11 |