Why is this an issue?
When calling delete
on an object of incomplete type, the calling code does not have enough information to do the action properly (it
does not know if this object has a trivial or a nontrivial destructor, if it has overloaded the delete
operator…). Therefore, deleting a
pointer to such an object can lead to undefined behavior.
Noncompliant code example
class Body;
class Handle {
public:
Handle();
~Handle() {
delete impl; // Noncompliant, Body is incomplete
}
private:
Body * impl;
};
Compliant solution
// In header file
class Body;
class Handle {
public:
Handle();
~Handle();
// Add other special member functions to respect the rule of five
private:
Body * impl;
};
// In implementation file
#include "Handle.h"
#include "Body.h" // Now Body is complete
Handle::~Handle(){
delete impl; // Compliant, at this point "Body" is a complete class
}
Or, with modern resource handling:
// In header file
class Body;
class Handle {
public:
Handle();
~Handle();
private:
std::unique_ptr<Body> impl; //Compliant
};
// In implementation file
#include "Handle.h"
#include "Body.h" // Now Body is complete
Handle::Handle() : impl{new Body{}} {}
Handle::~Handle() = default; // since "Body" is complete, it can be destroyed by unique_ptr