title: Exception to the Rule of Three?
body: <p>I've read a lot about the C++ <a href="https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three">Rule of Three</a>. Many people swear by it. But when the rule is stated, it almost always includes a word like "usually," "likely," or "probably," indicating that there are exceptions. I haven't seen much discussion of what these exceptional cases might be -- cases where the Rule of Three does not hold, or at least where adhering to it doesn't offer any advantage.</p>
  
  <p><strong>My question is whether my situation is a legitimate exception to the Rule of Three.</strong> I believe that in the situation I describe below, an explicitly defined copy constructor and copy assignment operator are necessary, but the default (implicitly generated) destructor will work fine. Here is my situation:</p>
  
  <p>I have two classes, A and B. The one in question here is A. B is a friend of A. A contains a B object. B contains an A pointer which is intended to point to the A object that owns the B object. B uses this pointer to manipulate private members of the A object. B is never instantiated except in the A constructor. Like this:</p>
  
  <pre><code>// A.h
  
  #include "B.h"
  
  class A
  {
  private:
      B b;
      int x;
  public:
      friend class B;
      A( int i = 0 )
      : b( this ) {
          x = i;
      };
  };
  </code></pre>
  
  <p>and...</p>
  
  <pre><code>// B.h
  
  #ifndef B_H // preprocessor escape to avoid infinite #include loop
  #define B_H
  
  class A; // forward declaration
  
  class B
  {
  private:
      A * ap;
      int y;
  public:
      B( A * a_ptr = 0 ) {
          ap = a_ptr;
          y = 1;
      };
      void init( A * a_ptr ) {
          ap = a_ptr;
      };
      void f();
      // this method has to be defined below
      // because members of A can't be accessed here
  };
  
  #include "A.h"
  
  void B::f() {
      ap-&gt;x += y;
      y++;
  }
  
  #endif
  </code></pre>
  
  <p>Why would I set up my classes like that? I promise, I have good reasons. These classes actually do way more than what I've included here.</p>
  
  <p>So the rest is easy, right? No resource management, no Big Three, no problem. Wrong! The default (implicit) copy constructor for A will not suffice. If we do this:</p>
  
  <pre><code>A a1;
  A a2(a1);
  </code></pre>
  
  <p>we get a new A object <code>a2</code> that is identical to <code>a1</code>, meaning that <code>a2.b</code> is identical to <code>a1.b</code>, meaning that <code>a2.b.ap</code> is still pointing to <code>a1</code>! This is not what we want. We must define a copy constructor for A that duplicates the functionality of the default copy constructor and then sets the new <code>A::b.ap</code> to point to the new A object. We add this code to <code>class A</code>:</p>
  
  <pre><code>public:
      A( const A &amp; other )
      {
          // first we duplicate the functionality of a default copy constructor
          x = other.x;
          b = other.b;
          // b.y has been copied over correctly
          // b.ap has been copied over and therefore points to 'other'
          b.init( this ); // this extra step is necessary
      };
  </code></pre>
  
  <p>A copy assignment operator is necessary for the same reason and would be implemented using the same process of duplicating the functionality of the default copy assignment operator and then calling <code>b.init( this );</code>.</p>
  
  <p>But there is no need for an explicit destructor; ergo this situation is an exception to the Rule of Three. Am I right?</p>