Когда вы используете unique_ptr<T>
для форвард объявленного типа T
, unique_ptr
деструктор требует T
завершено, но оператор присваивания перемещения также (и reset
), согласно этой таблице:
https://stackoverflow.com/a/6089065/1794803
Итак, для вашего pImpl
идиома, чтобы реализовать это правильно, вы должны объявить delete
и move assignment method
(который, как побочный эффект, помечает их как не встроенные):
class impl_t;
class A
{
std::unique_ptr<impl_t> p_impl;
public:
// Implement in A.cpp as A::~A() = default;
~A();
// Implemented in A.cpp as A& operator=(A&&) = default;
A& operator=(A&& he);
};
Но с тех пор std::unique_ptr
RAII-решение для динамической памяти, а вы pImpl
уже находится внутри класса, и вы все равно вынуждены написать деструктор, не лучше ли просто управлять необработанным указателем, поскольку ваш класс уже RAII-подобен с точки зрения p_impl
?:
class impl_t;
class A
{
impl_t* p_impl;
public:
~A(); // The destructor must be written anyway.
// The omitted move assignment destructor doesn't cause UB.
};
Разве это не лучшее решение? (+ определили или удалите свой собственный оператор копирования / перемещения, если вы хотите, чтобы класс был копируемым / подвижным или нет; но это «сознательный выбор»; однако, не пишите назначение перемещения для unique_ptr
это ошибка).
Используя unique_ptr
только спасает тебя за написанное delete p_impl
в деструкторе, который вы должны объявить в любом случае.
unique_ptr
является отличным выбором для локальных динамических объектов, которые будут уничтожены даже в случае исключений, но для «атрибутов» вы ничего не экономите, кроме возможности получить UB, если вы не помните, что вам нужно переписать оператор присваивания перемещения.
Ну, используя std::unique_ptr
избавляет вас от беспокойства с явным delete
для p_impl
.
Кроме того, он должен хорошо работать в случаях одновременного доступа и исключительных случаях в конструкторе (что, кажется, не гарантируется использованием необработанного указателя и new
сам).
std :: unique_ptr должен быть предпочтительным способом для pimpl. Для справки см. Выступление Херба Саттера на CppCon16 около 10 минут.
Причина в том, что это предотвратит случайную смену прыща при проведении RAII.