При использовании unique_ptr<T>
для форвардного заявленного типа T
, то unique_ptr
деструктора требует T
завершено, но оператор присваивания движения, а также (и reset
), в соответствии с этой таблицей:C++/pimpl: raw указатель или unique_ptr? Какой лучший выбор?
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-решение для динамической памяти, а вы уже находитесь в классе, и вы вынуждены писать деструктор в любом случае, не лучше ли просто управлять необработанным указателем, так как вы класс уже 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» без пользовательского удаления сопоставим с необработанным указателем с точки зрения размера, после оптимизации. – skypjack