swap函数的实现方式

本文讨论了C++中swap函数的不同实现方式,包括默认版本、针对指针存储数据的特化版本、类模板的全特化以及非成员函数的实现。详细解释了在类模板和普通类中如何特化std::swap,以及调用这些版本的顺序规则。总结了default swap、member swap、non-member swap和std::swap全特化版本在实际编程中的应用。
摘要由CSDN通过智能技术生成

默认版本

namespace std
{
    template<typename T>
    void swap(T & a,T & b)
    {
        T temp(a);
        a=b;
        b=temp;
    }

}

如果类采用指针存储数据,则默认交换方式会变得低效。因为只用交换两个指针便能实现两个对象的交换。因此需要特化版本的swap,由于指针是私有成员,因此需要一个公有成员函数swap,完成实际的交换。然后由特化版本的swap调用该公有成员函数。我们不能修改namespace std的内容但我们可以为我们自定义类型完全特化标准模板。

全特化版本

class WidgetImpl
{
private:
    int a,b,c;
    std::vector<int> v;
};

class Widget
{
public:
    Widget(const Widget & rhs);
    Widget & operator=(const Widget & rhs)
    {
        *p=*rhs.p;
        return *this;
    }
    void swap(Widget & other)
    {
        using std::swap;
        swap(p, other.p);
    }
private:
    WidgetImpl * p;
};
namespace std
{
    template<>
    void swap<Widget>(Widget & a,Widget & b)
    {
        a.swap(b);
    }
}

如果处理的是类模板而不是类,则情况又不同了。因为函数模板(默认版本swap)只能全特化而不能偏特化。
因此不能写成

namespace std
{
    template<typename T>
    void swap<Widget<T>>(Widget<T> & a,Widget<T> & b)
    {
        a.swap(b);
    }
}

面对这种情况,惯常做法是为它添加一个重载版本。我们可以全特化std内的template,但不能给std添加新的template。因此不能将非成员swap声明为std::swap偏特化版本或者重载版本。采用的策略为将非成员swap和模板类放在同一个命名空间。

非成员函数,非std::swap版本

namespace WidgetStuff
{
    template<typename T>
    class Widget
    {
    };

    template<typename T>
    void swap(Widget<T> & a,Widget<T> & b)
    {
        a.swap(b);
    }
}

如果不额外使用某个命名空间,那么也可以,但会都处于global命名空间。这种做法对class和class template都行得通。但对于class还是应该特化一个std::swap版本。因为编写代码时可能强制限定std::swap版本。

有这么多版本的swap,那么实际调用哪个版本呢?你希望的是调用T的专属版本,并在该版本不存在时调用std内的一般版本。

template<typename T>
void dosometing(T & a,T & b)
{
    using std::swap;

    swap(a,b);
}

首先会在T所在命名空间或者global作用域内寻找任何T专属swap,如果没有找到,由于using std::swap;的存在,则会调用std内的版本,首先看有没有特化版本,然后再是一般版本。
综上,一共有default swap、member swap、non-member swap、std::swap全特化版本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值