unique_ptr, пользовательские удаления и Rule of Zero
Я пишу класс, который использует два объекта, созданные с использованием интерфейса C. Объекты выглядят так:
typedef struct... foo_t;
foo_t* create_foo(int, double, whatever );
void delete_foo(foo_t* );
(аналогично для bar_t
). Поскольку C++11, я хочу обернуть их в умный указатель, чтобы мне не пришлось писать какие-либо специальные методы. Класс будет обладать уникальным владением двумя объектами, поэтому unique_ptr
логически имеет смысл... но мне все равно придется написать конструктор:
template <typename T>
using unique_ptr_deleter = std::unique_ptr<T, void(*)(T*)>;
struct MyClass {
unique_ptr_deleter<foo_t> foo_;
unique_ptr_deleter<bar_t> bar_;
MyClass()
: foo_{nullptr, delete_foo}
, bar_{nullptr, delete_bar}
{ }
~MyClass() = default;
void create(int x, double y, whatever z) {
foo_.reset(create_foo(x, y, z));
bar_.reset(create_bar(x, y, z));
};
С другой стороны, с shared_ptr
Мне не пришлось бы писать конструктор или использовать псевдоним типа, так как я мог просто передать delete_foo
в reset()
- хотя это сделало бы мой MyClass
копируемый, и я не хочу этого.
Как правильно написать MyClass
с помощью unique_ptr
семантика и до сих пор придерживаться правила ноль?
1 ответ
Вашему классу не нужно объявлять деструктор (он получит правильную реализацию по умолчанию, независимо от того, объявите ли вы его по умолчанию), поэтому все еще соблюдает "Правило нуля".
Тем не менее, вы можете улучшить это, сделав объекты-функции удаления указателями, а не указателями:
template <typename T> struct deleter;
template <> struct deleter<foo_t> {
void operator()(foo_t * foo){delete_foo(foo);}
};
template <> struct deleter<bar_t> {
void operator()(bar_t * bar){delete_bar(bar);}
};
template <typename T>
using unique_ptr_deleter = std::unique_ptr<T, deleter<T>>;
Это имеет несколько преимуществ:
unique_ptr
не нужно хранить дополнительный указатель- функция удаления может быть вызвана напрямую, а не через указатель
- вам не нужно писать конструктор; конструктор по умолчанию будет делать правильные вещи.