Рассмотрим этот классический пример, который используется для объяснения того, что не следует делать с объявлениями вперед:
//in Handle.h file
class Body;
class Handle
{
public:
Handle();
~Handle() {delete impl_;}
//....
private:
Body *impl_;
};
//---------------------------------------
//in Handle.cpp file
#include "Handle.h"
class Body
{
//Non-trivial destructor here
public:
~Body () {//Do a lot of things...}
};
Handle::Handle () : impl_(new Body) {}
//---------------------------------------
//in Handle_user.cpp client code:
#include "Handle.h"
//... in some function...
{
Handle handleObj;
//Do smtg with handleObj...
//handleObj now reaches end-of-life, and BUM: Undefined behaviour
}
Я понимаю из стандарта, что это дело направлено в сторону UB, поскольку деструктор Body не является тривиальным. То, что я пытаюсь понять, на самом деле является основной причиной этого.
Я имею в виду, что проблема, похоже, "срабатывает" из-за того, что Handle dtor является встроенным, и поэтому компилятор делает что-то вроде следующего "встроенного расширения" (почти псевдокод здесь).
inline Handle::~Handle()
{
impl_->~Body();
operator delete (impl_);
}
Во всех единицах перевода (только Handle_user.cpp
в этом случае), где экземпляр Handle может быть уничтожен, не так ли?
Я просто не могу этого понять: хорошо, при создании вышеупомянутого встроенного расширения компилятор не имеет полного определения класса Body, но почему он не может просто разрешить компоновщик для объекта impl_->~Body()
, и поэтому он вызывает функция деструктора тела, которая фактически определена в файле реализации?
Я пропустил что-то большое здесь (и в этом случае извините за глупый вопрос)? Если это не так, мне просто интересно понять обоснование этого.