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

缺省情况下swap动作可由标准程序库提供的swap算法完成。

namespace std

{

     template <typename T>

       void swap (T& a, T& b)

       {

                  T temp(a);

                  a=b;

                  b= temp;

       }

}

但是使用默认额swap效率非常低,例如:

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,但缺省的swap算法不知道这一点。他不只复制三个Widget,还复制三个WidgetImpl对象。效率非常低。

我们希望告诉std::swap:当Widget被置换时真正该做的是置换其内部的pImpl指针:将是std::swap针对Widget特化。

例如:

namesapce std

{

        template<>

          void swap<Wideget>(Widget & a, Wideget & b)            //这是特化版本。

               {

                    swap(a.pImpl, b.pImpl);

                 }

}

函数一开始的“template<>"表示它是std::swap的一个特化版本。

通常我们不能够(不被允许)改变std命名空间内额任何东西,但是可以(被允许)为标准template( 如swap) 制造特化版本:

以上不能通过是因为它企图访问a和b内的pImpl指针,而那是private.我们可以将这个特化版本声明为friend,但和以往的规矩不太一样,我们令Widget声明为一个名为swap的public成员函数做真正的置换工作,然后将std::swap特化,令它用该成员函数:

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);

        }

}            //可以通过!

偏特化:

namespace std

{

           template<typeaname T >

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

              {

                        a.swap(a);             //错误不合法!

                }

}

我们企图偏特化一个模板函数,但是C++只允许我们对模板类偏特化。

当你打算偏特化一个模板函数时,通常做法是简单委为它添加一个重载版本:

      namespace std

              template<typename T>

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

                    {

                               a.swap(b):

                     }

}

但是这也不合法!一般而言,重载模板函数没有问题,但std是个特殊的命名空间,其管理规则也比较特殊,客户可以全特化std的template,但是不可以添加新的template到std里头。std的内容完全有C++标准委员会决定的。

答案很简单,我们还是声明一个非成员函数的swap让他调用成员函数的swap,但不再将那个非成员函数声明为std::swap的特化版或者重载版本:

namespac WidgetStuff

{

          ...

          template<typename T>

             class Widget{  ...};                        //内含public的成员函数,调用private变量,调用下面的swap

            ...

         template<typename T>

          void swap(Wideget<T> & a, Widget<T> & b)        //这里的swap不属于std命名空间

            {

                             a.swap(b);

                }

}

如果你希望调用T 专属版本,并在该版本不存在得情况下调用std内的版本时:

template<typename T>

void dosomething ( T & obj1, T & obj 2)

{

     using std:: swap:

        ....

      swap(obj1, obj2);

          ...

}

一旦编译器看到对swap得调用,他们便查找适当得swap并调用,C++名称查找法则确保找到全局作用域或者T所在得命名空间内得任何T专属得swap 。如果T是Widget并位于命名空间WidgetStuff内,编译器会找出WidgetStuff的Swap,如果没有T专属的swap存在,编译器就会使用std内的swap,着的感谢std::swap的声明式让std:;swap在函数内曝光。

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值