станд.:: auto_ptr или повышение:: shared_ptr для pImpl идиомы?

16
задан Oleg Svechkarenko 3 October 2012 в 12:27
поделиться

6 ответов

Вы не должны действительно использовать станд.:: auto_ptr для этого. Деструктор не будет видим в точке, Вы объявляете станд.:: auto_ptr, таким образом, это нельзя было бы назвать правильно. Это предполагает, что Вы вперед объявляете свой pImpl класс и создаете экземпляр в конструкторе в другом файле.

, Если Вы используете повышение:: scoped_ptr (никакая потребность в shared_ptr здесь, Вы не будете совместно использовать pimpl ни с какими другими объектами, и это осуществляется scoped_ptr, являющимся noncopyable), Вам только нужен pimpl деструктор, видимый в точке, которую Вы вызываете scoped_ptr конструктором.

, Например,

// in MyClass.h

class Pimpl;

class MyClass 
{ 
private:
    std::auto_ptr<Pimpl> pimpl;

public: 
    MyClass();
};

// Body of these functions in MyClass.cpp

Здесь, компилятор генерирует деструктор MyClass. Который должен назвать деструктор auto_ptr. В точке, где auto_ptr деструктор инстанцируют, Pimpl является неполным типом. Таким образом в к auto_ptr деструктору, когда это удаляет объект Pimpl, это не будет знать, как назвать деструктор Pimpl.

повышение:: scoped_ptr (и shared_ptr) не имеют этой проблемы, потому что при вызове конструктора scoped_ptr (или метод сброса) это также делает эквивалентное указателю функции, которое это будет использовать вместо вызова, удаляют. Ключевой пункт здесь - то, что это инстанцирует функции освобождения, когда Pimpl не является неполным типом. Как примечание стороны, shared_ptr позволяет Вам определять пользовательское освобождение функция, таким образом, можно использовать для него для вещей как дескрипторы GDI или независимо от того, что можно хотеть - но это - излишество для потребностей здесь.

, Если Вы действительно хотите использовать станд.:: auto_ptr, тогда необходимо проявить дополнительную заботу путем проверки, что Вы определяете свой деструктор MyClass в MyClass.cpp, когда Pimpl полностью определяется.

// in MyClass.h

class Pimpl;

class MyClass 
{ 
private:
    std::auto_ptr<Pimpl> pimpl;

public: 
    MyClass();
    ~MyClass();
};

и

// in MyClass.cpp

#include "Pimpl.h"

MyClass::MyClass() : pimpl(new Pimpl(blah))
{
}

MyClass::~MyClass() 
{
    // this needs to be here, even when empty
}

компилятор генерирует код, разрушают всех членов MyClass эффективно 'в' пустом деструкторе. Таким образом в точке auto_ptr деструктор инстанцируют, Pimpl больше не является неполным, и компилятор теперь знает, как назвать деструктор.

Лично, я не думаю, что это стоит стычки проверки, что все корректно. Существует также риск, что кто-то приедет позже и уберет код путем удаления на вид избыточного деструктора. Таким образом, просто более безопасно повсюду вокруг пойти с повышением:: scoped_ptr для такого рода вещи.

38
ответ дан 30 November 2019 в 15:35
поделиться

Я склонен использовать auto_ptr. Обязательно сделайте Ваш класс noncopyable (объявите частную копию ctor & оператор =, или иначе наследовались boost::noncopyable). Если Вы используете auto_ptr, одна морщина - то, что необходимо определить невстроенный деструктор, даже если тело пусто. (Это вызвано тем, что, если Вы позволяете компилятору генерировать деструктор по умолчанию, impl, будет неполный тип, когда вызов к delete impl_ сгенерирован, вызвав неопределенное поведение).

существует мало для выбора между auto_ptr & указатели повышения. Я склонен не использовать повышение на стилистических основаниях, если стандартная альтернатива библиотеки сделает.

12
ответ дан 30 November 2019 в 15:35
поделиться

Альтернатива повышения std::auto_ptr boost::scoped_ptr. Основное различие от auto_ptr - то, что boost::scoped_ptr noncopyable.

См. эта страница для получения дополнительной информации.

4
ответ дан 30 November 2019 в 15:35
поделиться

повышение:: shared_ptr особенно адаптируется для работы на pimpl идиому. Одно из основных преимуществ - то, что это позволяет не определять деструктор для класса, содержащего pimpl. Общая политика владения, возможно, оба преимущества и недостаток. Но в более позднем случае можно определить конструктора копии правильно.

4
ответ дан 30 November 2019 в 15:35
поделиться

Если Вы действительно педантичны нет никакой абсолютной гарантии, что использование auto_ptr участник не требует полного определения auto_ptr шаблонный параметр в точке, в которой это используется. Однако я никогда не видел, что это не работает.

Одно изменение должно использовать const auto_ptr. Это работает, пока Вы можете создать свой 'pimpl' с новым выражением в списке инициализатора и гарантируете, что компилятор не может генерировать конструктора копии значения по умолчанию и методы присвоения. Невстроенный деструктор для класса включения все еще должен быть обеспечен.

При прочих равных условиях, я одобрил бы реализацию, которая пользуется просто стандартными библиотеками, поскольку это сохраняет вещи более портативными.

1
ответ дан 30 November 2019 в 15:35
поделиться

Не так старайтесь стрелять себе в ногу в C++, у Вас есть много возможностей:) Нет никакой реальной потребности использовать любой автоматические указатели, так как Вы отлично знаете, когда Ваш объект должен войти и из жизни (в Вашем конструкторе (конструкторах) и деструкторе).

Сохраняют его простым.

-8
ответ дан 30 November 2019 в 15:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: