Вы не должны использовать std :: auto_ptr для этого. Деструктор не будет виден в тот момент, когда вы объявляете std :: auto_ptr, поэтому он может быть вызван неправильно. Это предполагает, что вы можете объявить класс pImpl и создать экземпляр внутри конструктора в другом файле.
Если вы используете boost :: scoped_ptr (здесь нет необходимости в shared_ptr, вы не будете делиться pimpl с любыми другими объектами, что обусловлено тем, что scoped_ptr не копируется ), вам нужен только деструктор pimpl, видимый в той точке, где вы вызываете конструктор scoped_ptr.
1009 * Е.Г. *
// 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.
boost :: scoped_ptr (и shared_ptr) не имеют этой проблемы, потому что когда вы вызываете конструктор scoped_ptr (или метод сброса), он также делает эквивалентный указатель функции, который он будет использовать вместо вызова delete , Ключевым моментом здесь является то, что он создает функцию освобождения, когда Pimpl не является неполным типом. В качестве примечания, shared_ptr позволяет вам указать пользовательскую функцию освобождения , так что вы можете использовать ее для таких вещей, как дескрипторы GDI или для чего-либо еще, что вам захочется - но это излишне для ваших нужд.
Если вы действительно хотите использовать std :: 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 больше не является неполным, и компилятор теперь знает, как вызвать деструктор.
Лично я не думаю, что стоит того, чтобы убедиться, что все правильно. Существует также риск того, что кто-нибудь придет позже и исправит код, удалив, казалось бы, избыточный деструктор. Так что для таких вещей просто безопаснее использовать boost :: scoped_ptr.