Pimpl с std::unique_ptr в производном классе
Я не понимаю следующий сценарий. Речь идет об использовании идиомы pimpl на основе std::unique_ptr
в производном классе. Дана простая иерархия классов, объявленная следующим образом:
class Foo
{
public:
virtual ~Foo();
//...
};
struct X;
class Bar : public Foo
{
public:
~Bar();
//...
private:
std::unique_ptr<X> _d;
};
Я показываю только код, соответствующий моему вопросу.
Представьте себе класс Foo
будучи некоторым интерфейсом и классом 'Bar', который его реализует. Я хочу использовать идиому pimpl в Bar
, Деструкторы являются виртуальными и определены в соответствующих файлах cpp. Также полное определение struct X
, который только объявлен вперед, доступен в cpp, так что для деструктора Bar
деструктор std::unique_ptr<X>::~unique_ptr()
могут быть созданы Когда я пытаюсь создать экземпляр Bar
Я бы ожидал, что это сработает
int main()
{
Bar b;
}
Вместо этого я получаю сообщение об ошибке компиляции с неопределенным типом 'X', за которым следует сообщение, что невозможно удалить неполный тип (в Visual Studio 2013 Update 2). Однако, если я явно добавлю конструктор по умолчанию в Bar
, main()
компилирует / строит правильно.
class Foo
{
public:
virtual ~Foo();
};
struct X;
class Bar : public Foo
{
public:
Bar();
~Bar();
private:
std::unique_ptr<X> _d;
};
Я не вижу соответствия между наличием конструкторов по умолчанию в этой иерархии классов и полнотой struct X
в контексте std::unique_ptr<X>
в Bar
, Может ли кто-нибудь объяснить или указать на возможно уже существующее объяснение?
1 ответ
Проблема в том, что конструктор по умолчанию добавлен в Bar
должен позвонить std::unique_ptr<X>
деструктор на всякий случай Bar
конструктор выдает исключение.
Но std::unique_ptr<X>::~unique_ptr()
вызывает Deleter unique_ptr: std::default_delete<X>
- что требует X
быть полным типом. [Unique.ptr.single.dtor]
Когда вы сами объявляете конструктор, его создание не происходит, потому что конструктор только объявляется и, таким образом, связывается в более поздний момент времени, и компилятор с удовольствием ест ваш код.