Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Consider a common application of a handle/body idiom that implements an abstract data type by a handle that contains a pointer to an implementation class.

Code Block
bgColor#FFcccc
langcpp
class Body; // incomplete class declaration

class Handle {
  public:
    Handle();
    ~Handle() { delete impl_; } // deletion of pointer to incomplete class
    // ...
  private:
    Body *impl_;
};

...

The deletion of impl_ should be moved to a part of the code where Body is defined.

Code Block
bgColor#ccccff
langcpp
class Body {
    // ...
};

Handle::~Handle() { delete impl_; } // correct.

...

Alternatively, an appropriate smart pointer may be used in place of a raw pointer.

Code Block
bgColor#ccccff
langcpp
class Handle {
  public:
    Handle();
    ~Handle() {} // correct.
    // ...
  private:
    std::tr1::shared_ptr<Body> impl_;
};

...

Similarly, while it is possible to cast a pointer or reference to an incomplete class, it is never a good idea to do so. Casting a class address often involves an adjustment of the address by a fixed amount that can only be determined after the layout and inheritance structure of the class is known, and this information is not available in the case of an incomplete class.

Code Block
bgColor#FFcccc
langcpp
class B {
    // ...
};
B *getMeSomeSortOfB();
// ...
class D; // incomplete declaration
// ...
B *bp = getMeSomeSortOfB();
D *dp = (D *)bp; // old-stlye cast: legal, but inadvisable
dp = reinterpret_cast<D *>(bp); // new-style cast: legal, but inadvisable

...