title: Pimpl idiom using shared_ptr working with incomplete types
body: <p>I'm reading Effective Modern C++ by Scott Meyers and he's discussing the use of the pimpl idiom and pointing to the implementation class with <code>unique_ptr</code>, but there is an issue of special member functions (such as destructors) requiring the type to be complete. This is because <code>unique_ptr</code>'s default deleter statically asserts whether the type to be deleted is complete, before <code>delete p</code> is used. So any special member functions of the class must be defined in the implementation file (rather than being compiler-generated), <em>after</em> the implementation class has been defined.  </p>
  
  <p>At the end of the chapter, he mentions there is no need to define special member functions in the implementation file if the smart pointer used is <code>shared_ptr</code>, and this stems from the way it supports a custom deleter. To quote:</p>
  
  <blockquote>
    <p>The difference in behavior between std::unique_ptr and std::shared_ptr for
    pImpl pointers stems from the differing ways these smart pointers support custom
    deleters. For std::unique_ptr, the type of the deleter is part of the type of the smart
    pointer, and this makes it possible for compilers to generate smaller runtime data
    structures and faster runtime code. A consequence of this greater efficiency is that
    pointed-to types must be complete when compiler-generated special functions (e.g.,
    destructors or move operations) are used. For std::shared_ptr, the type of the
    deleter is not part of the type of the smart pointer. This necessitates larger runtime
    data structures and somewhat slower code, but pointed-to types need not be complete
    when compiler-generated special functions are employed.</p>
  </blockquote>
  
  <p>Despite this, I still can't see why <code>shared_ptr</code> could still work without the class being complete. It seems like the only reason there is no compiler error when using <code>shared_ptr</code> is because there is no static assertion like <code>unique_ptr</code> had, and that undefined runtime behaviour could instead occur because of this lack of assertion. </p>
  
  <p>I don't know the implementation of the <code>shared_ptr</code>'s destructor, but (from reading C++ Primer) I gathered the impression it works something like:</p>
  
  <pre><code>del ? del(p) : delete p;
  </code></pre>
  
  <p>Where <code>del</code> is a pointer or function object to the custom deleter. <a href="http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr" rel="noreferrer">Cppreference</a> also makes it clear the <code>shared_ptr</code> destructor with no custom deleter uses <code>delete p</code></p>
  
  <blockquote>
    <p>3) Uses the delete-expression <code>delete ptr</code> if <code>T</code> is not an array type; .... <strong>Y must be a complete type</strong>. The delete expression must be well formed, have well-defined behavior and not throw any exceptions.</p>
  </blockquote>
  
  <p>Emphasis on the fact that the deleted type must be complete. A minimal example of the pimpl idiom:</p>
  
  <pre><code>//widget.h
  
  #ifndef WIDGET
  #define WIDGET
  
  #include &lt;memory&gt;
  
  class Widget{
  public:
      Widget();
  private:
      struct Impl;
      std::shared_ptr&lt;Impl&gt; pImpl;
  
  };
  
  #endif // WIDGET
  
  //widget.cpp
  
  #include &lt;string&gt;
  #include "Widget.h"
  
  struct Widget::Impl{
      std::string name;
  };
  
  Widget::Widget(): pImpl(new Impl) {}
  
  //main.cpp
  
  #include &lt;iostream&gt;
  #include "Widget.h"
  
  int main(){
      Widget a;
  }
  </code></pre>
  
  <p>When <code>Widget a</code> in <code>main.cpp</code> is compiled, the template of <code>shared_ptr</code> is instantited for type <code>Widget</code> (within <code>main.cpp</code>) and presumably the resulting compiled destructor for <code>shared_ptr</code> contains execution of the line <code>delete pImpl</code>, because I have not supplied a custom deletor. However at that point, <code>Impl</code> still has not been defined, yet the line <code>delete pImpl</code> is executed. This, surely, is undefined behaviour?</p>
  
  <p>So how is it that when using the pimpl idiom with <code>shared_ptr</code>, I don't have to define the special member functions in the implementation file to avoid undefined behaviour?</p>