谈谈C++中的swap函数

1,最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符。

template <class T> void swap ( T& a, T& b )  
{  
  T c(a); a=b; b=c;  
}  
需要构建临时对象,一个拷贝构造,两次赋值操作。

2,针对int型优化:

void swap(int & __restrict a, int & __restrict b)  
{  
a ^= b;  
b ^= a;  
a ^= b;  
}  
无需构造临时对象,异或
因为指针是int,所以基于这个思路可以优化1:

template <typename T> void Swap(T & obj1,T & obj2)  
{  
    unsigned char * pObj1 = reinterpret_cast<unsigned char *>(&obj1);  
    unsigned char * pObj2 = reinterpret_cast<unsigned char *>(&obj2);  
    for (unsigned long x = 0; x < sizeof(T); ++x)  
    {  
        pObj1[x] ^= pObj2[x];  
        pObj2[x] ^= pObj1[x];  
        pObj1[x] ^= pObj2[x];  
    }  
}  
3,针对内建类型的优化:  int, flaot, double 等,甚至重载运算符的用户自定义类型:向量,矩阵,图像等。。。


type  a; -- e.g 10
type  b; -- e.g 5


a = a+b ; -- a=15,b=5
b = a-b ; -- a=15,b=10
a= a -b ; -- a= 5,b=10


// 无需构造临时变量。使用基本运算操作符。

Ok, let's see.  
a = a + b;  
b = a - b;  
a = a - b;  
Let's introduce new names  
c = a + b;  
d = c - b;  
e = c - d;  
And we want to prove that d == a and e == b.  
d = (a + b) - b = a, proved.  
e = (a + b) - ((a + b) - b) = (a + b) - a = b, proved.  
For all real numbers.  
4,swap的一些特化:
std::string, std::vector各自实现了swap函数,


string中

template<class _Elem,  
    class _Traits,  
    class _Alloc> inline  
    void __CLRCALL_OR_CDECL swap(basic_string<_Elem, _Traits, _Alloc>& _Left,  
        basic_string<_Elem, _Traits, _Alloc>& _Right)  
    {   // swap _Left and _Right strings  
    _Left.swap(_Right);  
    }  
    void __CLR_OR_THIS_CALL swap(_Myt& _Right)  
        {   // exchange contents with _Right  
        if (this == &_Right)  
            ;   // same object, do nothing  
        else if (_Mybase::_Alval == _Right._Alval)  
            {   // same allocator, swap control information  
 #if _HAS_ITERATOR_DEBUGGING  
            this->_Swap_all(_Right);  
 #endif /* _HAS_ITERATOR_DEBUGGING */  
            _Bxty _Tbx = _Bx;  
            _Bx = _Right._Bx, _Right._Bx = _Tbx;  
            size_type _Tlen = _Mysize;  
            _Mysize = _Right._Mysize, _Right._Mysize = _Tlen;  
            size_type _Tres = _Myres;  
            _Myres = _Right._Myres, _Right._Myres = _Tres;  
            }  
        else  
            {   // different allocator, do multiple assigns  
            _Myt _Tmp = *this;  
            *this = _Right;  
            _Right = _Tmp;  
            }  
        }  

第二个swap(Right)进行判断,如果使用了相同的分配器,则直接交换控制信息,否则调用string::operator=进行拷贝赋值。。。所以建议优先使用swap函数,而不是赋值操作符。

vector中
template<class _Ty,  
    class _Alloc> inline  
    void swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right)  
    {   // swap _Left and _Right vectors  
    _Left.swap(_Right);  
    }  
    void swap(_Myt& _Right)  
        {   // exchange contents with _Right  
        if (this == &_Right)  
            ;   // same object, do nothing  
        else if (this->_Alval == _Right._Alval)  
            {   // same allocator, swap control information  
 #if _HAS_ITERATOR_DEBUGGING  
            this->_Swap_all(_Right);  
 #endif /* _HAS_ITERATOR_DEBUGGING */  
            this->_Swap_aux(_Right);  
            _STD swap(_Myfirst, _Right._Myfirst);  
            _STD swap(_Mylast, _Right._Mylast);  
            _STD swap(_Myend, _Right._Myend);  
            }  
        else  
            {   // different allocator, do multiple assigns  
            this->_Swap_aux(_Right);  
            _Myt _Ts = *this;  
            *this = _Right;  
            _Right = _Ts;  
            }  
        }  

vector的swap原理跟string完全一致,只有当当使用了不同分配器才进行字节拷贝。其余情况直接交换控制信息。

测试用例:

5,Copy and  Swap idiom
目的:C++异常有三个级别:基本,强,没有异常。通过创建临时对象然后交换,能够实现重载赋值操作符的强异常安全的执行。
Loki中智能指针 临时变量跟this交换,临时变量自动销毁~
SmartPtr& operator=(SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs)  
{  
    SmartPtr temp(rhs);  
    temp.Swap(*this);  
    return *this;  
}  


boost::share_ptr,share_ptr定义了自己的swap函数。

shared_ptr & operator=( shared_ptr const & r ) // never throws  
{  
    this_type(r).swap(*this);  
    return *this;  
}  
void swap(shared_ptr<T> & other) // never throws  
{  
    std::swap(px, other.px);  
    pn.swap(other.pn);  
}  

String::opreator=函数的优化:
最一般的写法,特点:使用const string& 传参防止临时对象。

String& String::operator =(const String & rhs)  
{  
    if (itsString)  
        delete [] itsString;  
    itsLen = rhs.GetLen();  
    itsString = new char[itsLen+1];  
    for (unsigned short i = 0;i<itsLen;i++)  
        itsString[i] = rhs[i];  
    itsString[itsLen] = '/0';  
    return *this;  
}  

优化1,防止自我间接赋值,a = b; c = b; a = c; 如果没有第一个if判断,当把c赋给a的时候,删除了a.itsString,后面的拷贝就会出错。注意是if(this==&rhs), 而不是if(*this==rhs) .

String& String::operator =(const String & rhs)  
{  
    if (this == &rhs)  
        return *this;  
    if (itsString)  
        delete [] itsString;  
    itsLen=rhs.GetLen();  
    itsString = new char[itsLen+1];  
    for (unsigned short i = 0;i<itsLen;i++)  
        itsString[i] = rhs[i];  
    itsString[itsLen] = '/0';  
    return *this;  
}  

优化2,不进行拷贝赋值,只是交换控制信息,而且是强异常安全:

String & String::operator = (String const &rhs)  
{  
    if (this != &rhs)  
        String(rhs).swap (*this); // Copy-constructor and non-throwing swap  
    // Old resources are released with the destruction of the temporary above  
    return *this;  
}  

优化3,以最原始的传值方式传参,避免临时对象创建:

String & operator = (String s) // the pass-by-value parameter serves as a temporary  
{  
   s.swap (*this); // Non-throwing swap  
   return *this;  
}// Old resources released when destructor of s is called.  

转自 点击打开链接


4,swap的一些特化:
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值