Effective C++ Ed. 3rd: Item 25 Consider support for non-throwing swap.

Contents:
  •     Default Swap
  •     Member Swaps
  •     Non-member swaps
  •     Specializations of std::swaps
  •     calls to swap

Swap has become a mainstay. Swap is a very useful function. It's important to implement it properly. Among many uses, it is a common mechanism for coping with the possibility of assignment to self. A typical implementation in std is:
namespace std {
template  <>        // typical implementation of std::swap;
void swap(T& a, T& b)         // swaps a's and b's values  
{
    T temp(a);
    a = b;
    b = temp;
  }
}

To override swap function:

class Widget {                     // same as above, except for the
public:                            // addition of the swap mem func
  ...
  void swap(Widget& other)
  {
    using std::swap;               // the need for this declaration
                                   // is explained later in this Item
    swap(pImpl, other.pImpl);      // to swap Widgets, swap their
  }                                // pImpl pointers

private:

  WidgetImpl *pImpl; // pointer to some other object
  ...
};
namespace std {
  template < >                      // revised specialization of
  void swap< widget > (Widget& a,     // std::swap
                    Widget& b)
  {
    a.swap(b);                     // to swap Widgets, call their
  }                                // swap member function
}


To override swap function for a template class:
template < typename T >
class WidgetImpl { ... };
template < typename T >
class Widget { ... };


Way1 and Way2 are wrong, but Way3 will work because it is okay to totally specialize templates in std, but it's not okay to add new templates to std.

Way1:
namespace std {
  template < typename T >
  void swap < widget > (Widget& a,      // error! illegal code!
                        Widget& b)
  { a.swap(b); }
}
Way2:
namespace std {
  template < typename T >             // an overloading of std::swap
  void swap(Widget& a,          // (note the lack of "<...>" after
            Widget& b)          // "swap")
  { a.swap(b); }                   // this isn't valid code
}
Way3://Make sure it doesn't throw exception
namespace WidgetStuff {
  ...                                     // templatized WidgetImpl, etc.
  template < typename T >                   // as before, including the swap
  class Widget { ... };                   // member function
  ...
  template < typename T >                    // non-member swap function;
  void swap(Widget& a,                 // not part of the std namespace
            Widget& b)                                        
  {
    a.swap(b);
  }
}
Client's Way:
template <>
void doSomething(T& obj1, T& obj2)
{
  using std::swap;           // make std::swap available in this function
  ...
  swap(obj1, obj2);          // call the best swap for objects of type T
  ...
}
prev | next

No comments:

Post a Comment