Simple version of

The following code will compile with warning:

class X;

void foo(X* x) {
    delete x;
}
Copy the code

Under GCC4.1.2, the compile error message is:

Warning: Possible problem detected in Invocation of delete operator: Warning: 'X' has incomplete type warning: Forward declaration of 'struct X' note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.Copy the code

This is because in foo, the compiler can’t see the full type of X and can’t determine two things:

  1. XIs there a custom destructor (or, rather, a non-trivial destructor)?
  2. XThere is no customoperator deleteFunction.

Without knowing these two things, the compiler can only handle delete X in the most general way:

  1. No destructors are called.
  2. Call globaloperator deleteUsually, this is to free the memory directly.

Daily edition

There is a common scenario that triggers the above question.

Here is a three-file project that uses the ‘pImpl’ method to hide the implementation, thus putting a STD ::auto_ptr in the interface class, which is very simple:

// test.h #include <memory> class A { class Impl; public: A(); void Func(); private: std::auto_ptr<Impl> mImpl; }; // test.cpp #include "test.h" #include <iostream> class A::Impl { public: void Func() { std::cout << "Func" << std::endl; }}; A::A(): mImpl(new Impl) {} void A::Func() { mImpl->Func(); } // main.cpp #include "test.h" int main() { A a; a.Func(); }Copy the code

This looks fine, but at compile time warning:

$g++ test.cpp main. CPP In destructor 'STD ::auto_ptr<_Tp>::~auto_ptr() [with _Tp = A::Impl]' : test.h:4: STD ::auto_ptr<_Tp>::~auto_ptr() [with _Tp = A::Impl] ': instantiated from here warning: possible problem detected in invocation of delete operator: warning: Invalid use of undefined type 'struct A::Impl' test.h:5: Warning: Forward declaration of 'struct A::Impl' Note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.Copy the code

The warning message is the same as the previous one, and it appears that the error occurred when the delete call was made. But where is delete called?

The answer is STD ::auto_ptr.

In the above code, we didn’t write A destructor for class A manually, because the destructor generated automatically by the compiler is what we want: to destruct the mImpl.

So what does an automatically generated destructor look like? Probably is:

A::~A() {
    mImpl.~std::auto_ptr<Impl>();
}
Copy the code

The expansion is basically a delete:

A::~A() {
    delete mImpl._M_ptr;
}
Copy the code

Where is this destructor? The C++ standard places auto-generated class member functions in the class definition, in test.h.

The problem is clear: when we compile main.cpp, we don’t see the full definition of A::Impl, but there is an automatically generated A::~A in which an incomplete class object is deleted!

solution

Write A destructor for A manually where you can see the full definition of A::Impl: test.cpp:

```cpp // test.h #include <memory> class A { class Impl; public: A(); ~A(); void Func(); private: std::auto_ptr<Impl> mImpl; }; // test.cpp #include "test.h" #include <iostream> class A::Impl { public: void Func() { std::cout << "Func" << std::endl; }}; A::A(): mImpl(new Impl) {} A::~A() {} void A::Func() { mImpl->Func(); }Copy the code

Related literature

  • Stackoverflow.com/questions/4…
  • Stackoverflow.com/questions/4…