第四部分(4)(条款25:考虑写出一个不抛出异常的swap函数)

来源:互联网 发布:大树网络 怎么样 编辑:程序博客网 时间:2024/04/29 23:04

条款25:考虑写出一个不抛出异常的swap函数

所谓swap两个对象,就是将两个对象的值彼此赋予对方。标准库可能是这样实现的:

namespace std{

  template<typename T>

  void swap(T& a,T&b)

  {

     T temp(a);

     a = b;

     b = temp;

  }

}

只要类型T支持copying(copy constructor and copy assignment)就可以了。

“以指针指向一个对象,内含真正的数据”这种表现形式就是“pimpl手法”,以 Widget class 为例:

class WidgetImpl{

 public:

  ...

 private:

  int a,b,c;

  std::vector<double> v;

  ...

};

class Widget{

 public:

  Widget(const Widget& rhs);

  Widget& operator=(const Widget& rhs)

  {

     ...

     *pImpl = *(rhs.pImpl);

     ... 

  }

    ...

  private:

   WidgetImpl* pImpl;

};

    在这里交换Widget对象,只需要交换pImpl指针就可以了,但是default swap算法不仅要复制三个Widget对象还要复制三个WidgetImpl。

  so,我们期望这样做

  namespace std{

   template<>

   void swap<Widget>(Widget& a, Widget& b)

   {

       swap(a.pImpl,b.Impl);//编译无法通过,因为pImpl是private

   }

 }

    我们不允许改变std内的任何空间,但是我们可以为标准template制造特化版本,如上面所示。当然我们可以将此特化版本声明为friend,但是这有违背以往的规矩:我们可以这样做:

  class Widget{

    public:

    ...

    void swap(Widget& other)

    {

      using std::swap;

      swap(pImpl,other.pImpl);

     }

    ...

  };

 namespace std{

  template<>

  void swap<Widget>(Widget& a,Widget& b)

  {

    a.swap(b);

  }

}

然而假设两个类都是template呢:

 template<typename T>

 class WidgetImpl{...};

 

 template<typename T>

 class Widget{...};

在Widget内部的swap函数不变,但是特化会变为:

namespace std{

  template<typename T>

  void swap<  Widget<T> >(Widget& a,Widget& b)

  { a.swap(b);  }

}

    C++只允许对class template实现偏特化,在function template偏特化是行不通的。我们习惯性的动作是做一个函数重载:

  namespace std{

   template<typename T>

   void swap(Widget<T>& a,Widget<T>& b)

   {  a.swap(b);  }

 }

    但是很不幸,C++标准委员会不允许我们对它已经定义好的东西膨胀,所以达不到我们预期的效果。我们可以这样做:

  namespace WidgetStuff{

   ...

  template<typename T>

  class Widget{...};

  ...

  template<typename T>

   void swap(Widget<T>& a,Widget<T>& b)

   { 

    a.swap(b);

   }

 }

现在我们达到了预期的效果。但是我们希望的是在使用的时候调用T的专属版本,并在该版本不存在的情况下调用std内的版本:

template<typename T>

void doSomething(T& obj1,T&obj2)

{

  using std::swap;

  ...

  swap(obj1,obj2);

  ...

这里需要注意错误的调用方式: std::swap(obj1,obj2);这会影响sdt选择函数。

原创粉丝点击