title: Placement-new vs gcc 4.4.3 strict-aliasing rules
body: <p>I've got some code that I've been using successfully for some years to implement a "variant-type object"; that is, a C++ object that can hold a values of various types, but only uses (approximately) as much memory as the largest of the possible types.  The code is similar in spirit to a tagged-union, except that it supports non-POD data types as well.  It accomplishes this magic by using a char buffer, placement new/delete, and reinterpret_cast&lt;>.</p>
  
  <p>I recently tried compiling this code under gcc 4.4.3 (with -O3 and -Wall), and got lots of warnings like this:</p>
  
  <pre><code>warning: dereferencing type-punned pointer will break strict-aliasing rules
  </code></pre>
  
  <p>From what I've read, this is an indication that the gcc's new optimizer might generate 'buggy' code, which I obviously would like to avoid.</p>
  
  <p>I've pasted a 'toy version' of my code below; is there anything I can do to my code to make it safer under gcc 4.4.3, while still supporting non-POD data types?  I know that as a last resort I could always compile the code with -fno-strict-aliasing, but it would be nice to have code that doesn't break under optimization so I'd rather not do that.</p>
  
  <p>(Note that I'd like to avoid introducing a boost or C++0X dependency into the codebase, so while boost/C++0X solutions are interesting, I'd prefer something a little more old-fashioned)</p>
  
  <pre><code>#include &lt;new&gt;
  
  class Duck
  {
  public:
     Duck() : _speed(0.0f), _quacking(false) {/* empty */}
     virtual ~Duck() {/* empty */}  // virtual only to demonstrate that this may not be a POD type
  
     float _speed;
     bool _quacking;
  };
  
  class Soup
  {
  public:
     Soup() : _size(0), _temperature(0.0f) {/* empty */}
     virtual ~Soup() {/* empty */}  // virtual only to demonstrate that this may not be a POD type
  
     int _size;
     float _temperature;
  };
  
  enum {
     TYPE_UNSET = 0,
     TYPE_DUCK,
     TYPE_SOUP
  };
  
  /** Tagged-union style variant class, can hold either one Duck or one Soup, but not both at once. */
  class DuckOrSoup
  {
  public:
     DuckOrSoup() : _type(TYPE_UNSET) {/* empty*/}
     ~DuckOrSoup() {Unset();}
  
     void Unset() {ChangeType(TYPE_UNSET);}
     void SetValueDuck(const Duck &amp; duck) {ChangeType(TYPE_DUCK); reinterpret_cast&lt;Duck*&gt;(_data)[0] = duck;}
     void SetValueSoup(const Soup &amp; soup) {ChangeType(TYPE_SOUP); reinterpret_cast&lt;Soup*&gt;(_data)[0] = soup;}
  
  private:
     void ChangeType(int newType);
  
     template &lt;int S1, int S2&gt; struct _maxx {enum {sz = (S1&gt;S2)?S1:S2};};
     #define compile_time_max(a,b) (_maxx&lt; (a), (b) &gt;::sz)
     enum {STORAGE_SIZE = compile_time_max(sizeof(Duck), sizeof(Soup))};
  
     char _data[STORAGE_SIZE];
     int _type;   // a TYPE_* indicating what type of data we currently hold
  };
  
  void DuckOrSoup :: ChangeType(int newType)
  {
     if (newType != _type)
     {
        switch(_type)
        {
           case TYPE_DUCK: (reinterpret_cast&lt;Duck*&gt;(_data))-&gt;~Duck(); break;
           case TYPE_SOUP: (reinterpret_cast&lt;Soup*&gt;(_data))-&gt;~Soup(); break;
        }
        _type = newType;
        switch(_type)
        {
           case TYPE_DUCK: (void) new (_data) Duck();  break;
           case TYPE_SOUP: (void) new (_data) Soup();  break;
        }
     }
  }
  
  int main(int argc, char ** argv)
  {
     DuckOrSoup dos;
     dos.SetValueDuck(Duck());
     dos.SetValueSoup(Soup());
     return 0;
  }
  </code></pre>