2016-12-10 16 views
2

При использовании 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, если не помните, что вам нужно переписать этот ход оператор присваивания.

ответ

4

Ну, используя std::unique_ptr искупает вас от возитесь с явной delete для p_impl.

Также он должен хорошо работать в случаях параллельного доступа и исключительных случаев в конструкторе (который, похоже, не гарантируется с использованием необработанного указателя и new).

+0

Кроме того, «std :: unique_ptr» без пользовательского удаления сопоставим с необработанным указателем с точки зрения размера, после оптимизации. – skypjack

0

std :: unique_ptr должен быть предпочтительным способом для pimpl согласно. Для справки см. Herb Sutter's talk at CppCon16 около 10 минут. Причина в том, что это предотвратит вас от случайного изменения вашего пимбла при сохранении RAII.

 Смежные вопросы

  • Нет связанных вопросов^_^