码迷,mamicode.com
首页 > 编程语言 > 详细

swap C++用法

时间:2015-10-24 10:07:09      阅读:409      评论:0      收藏:0      [点我收藏+]

标签:

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

 

  1. template <class T> void swap ( T& a, T& b )  
  2. {  
  3.   T c(a); a=b; b=c;  
  4. }  

 

 

需要构建临时对象,一个拷贝构造,两次赋值操作。

2,针对int型优化:

 

  1. void swap(int & __restrict a, int & __restrict b)  
  2. {  
  3. a ^= b;  
  4. b ^= a;  
  5. a ^= b;  
  6. }  

 

 

无需构造临时对象,异或

因为指针是int,所以基于这个思路可以优化1:

 

 

  1. template <typename T> void Swap(T & obj1,T & obj2)  
  2. {  
  3.     unsigned char * pObj1 = reinterpret_cast<unsigned char *>(&obj1);  
  4.     unsigned char * pObj2 = reinterpret_cast<unsigned char *>(&obj2);  
  5.     for (unsigned long x = 0; x < sizeof(T); ++x)  
  6.     {  
  7.         pObj1[x] ^= pObj2[x];  
  8.         pObj2[x] ^= pObj1[x];  
  9.         pObj1[x] ^= pObj2[x];  
  10.     }  
  11. }  

 

 

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

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

 

  1. Ok, let‘s see.  
  2. a = a + b;  
  3. b = a - b;  
  4. a = a - b;  
  5. Let‘s introduce new names  
  6. c = a + b;  
  7. d = c - b;  
  8. e = c - d;  
  9. And we want to prove that d == a and e == b.  
  10. d = (a + b) - b = a, proved.  
  11. e = (a + b) - ((a + b) - b) = (a + b) - a = b, proved.  
  12. For all real numbers.  

 

 

4,swap的一些特化:

std::string, std::vector各自实现了swap函数,

string

 

  1. template<class _Elem,  
  2.     class _Traits,  
  3.     class _Alloc> inline  
  4.     void __CLRCALL_OR_CDECL swap(basic_string<_Elem, _Traits, _Alloc>& _Left,  
  5.         basic_string<_Elem, _Traits, _Alloc>& _Right)  
  6.     {   // swap _Left and _Right strings  
  7.     _Left.swap(_Right);  
  8.     }  
  9.     void __CLR_OR_THIS_CALL swap(_Myt& _Right)  
  10.         {   // exchange contents with _Right  
  11.         if (this == &_Right)  
  12.             ;   // same object, do nothing  
  13.         else if (_Mybase::_Alval == _Right._Alval)  
  14.             {   // same allocator, swap control information  
  15.  #if _HAS_ITERATOR_DEBUGGING  
  16.             this->_Swap_all(_Right);  
  17.  #endif /* _HAS_ITERATOR_DEBUGGING */  
  18.             _Bxty _Tbx = _Bx;  
  19.             _Bx = _Right._Bx, _Right._Bx = _Tbx;  
  20.             size_type _Tlen = _Mysize;  
  21.             _Mysize = _Right._Mysize, _Right._Mysize = _Tlen;  
  22.             size_type _Tres = _Myres;  
  23.             _Myres = _Right._Myres, _Right._Myres = _Tres;  
  24.             }  
  25.         else  
  26.             {   // different allocator, do multiple assigns  
  27.             _Myt _Tmp = *this;  
  28.             *this = _Right;  
  29.             _Right = _Tmp;  
  30.             }  
  31.         }  

 

 

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

 

vector

 

  1. template<class _Ty,  
  2.     class _Alloc> inline  
  3.     void swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right)  
  4.     {   // swap _Left and _Right vectors  
  5.     _Left.swap(_Right);  
  6.     }  
  7.     void swap(_Myt& _Right)  
  8.         {   // exchange contents with _Right  
  9.         if (this == &_Right)  
  10.             ;   // same object, do nothing  
  11.         else if (this->_Alval == _Right._Alval)  
  12.             {   // same allocator, swap control information  
  13.  #if _HAS_ITERATOR_DEBUGGING  
  14.             this->_Swap_all(_Right);  
  15.  #endif /* _HAS_ITERATOR_DEBUGGING */  
  16.             this->_Swap_aux(_Right);  
  17.             _STD swap(_Myfirst, _Right._Myfirst);  
  18.             _STD swap(_Mylast, _Right._Mylast);  
  19.             _STD swap(_Myend, _Right._Myend);  
  20.             }  
  21.         else  
  22.             {   // different allocator, do multiple assigns  
  23.             this->_Swap_aux(_Right);  
  24.             _Myt _Ts = *this;  
  25.             *this = _Right;  
  26.             _Right = _Ts;  
  27.             }  
  28.         }  

 

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

 

测试用例:

 

5,Copy and  Swap idiom

目的:C++异常有三个级别:基本,强,没有异常。通过创建临时对象然后交换,能够实现重载赋值操作符的强异常安全的执行。

Loki中智能指针 临时变量跟this交换,临时变量自动销毁~

 

  1. SmartPtr& operator=(SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs)  
  2. {  
  3.     SmartPtr temp(rhs);  
  4.     temp.Swap(*this);  
  5.     return *this;  
  6. }  

 

 

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

 

  1. shared_ptr & operator=( shared_ptr const & r ) // never throws  
  2. {  
  3.     this_type(r).swap(*this);  
  4.     return *this;  
  5. }  
  6. void swap(shared_ptr<T> & other) // never throws  
  7. {  
  8.     std::swap(px, other.px);  
  9.     pn.swap(other.pn);  
  10. }  

 

 

记得本科上C++课,老师特别喜欢拿String来举例子,面试题也特别喜欢String。。。下面说说String::opreator=函数的优化:

最一般的写法,特点:使用const string& 传参防止临时对象。

 

  1. String& String::operator =(const String & rhs)  
  2. {  
  3.     if (itsString)  
  4.         delete [] itsString;  
  5.     itsLen = rhs.GetLen();  
  6.     itsString = new char[itsLen+1];  
  7.     for (unsigned short i = 0;i<itsLen;i++)  
  8.         itsString[i] = rhs[i];  
  9.     itsString[itsLen] = ‘/0‘;  
  10.     return *this;  
  11. }  

 

 

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

 

  1. String& String::operator =(const String & rhs)  
  2. {  
  3.     if (this == &rhs)  
  4.         return *this;  
  5.     if (itsString)  
  6.         delete [] itsString;  
  7.     itsLen=rhs.GetLen();  
  8.     itsString = new char[itsLen+1];  
  9.     for (unsigned short i = 0;i<itsLen;i++)  
  10.         itsString[i] = rhs[i];  
  11.     itsString[itsLen] = ‘/0‘;  
  12.     return *this;  
  13. }  

 

 

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

 

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

 

 

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

 

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

 

 

最后这张方式主要是对C++新特性rvalue的优化,具体参见:http://en.wikibooks.org/wiki/More_C++_Idioms/Copy-and-swap 

 

附上网络版的String:

 

    1. #include <iostream>  
    2. #include <cstring>  
    3. using namespace std;  
    4. class String  
    5. {  
    6.         public:  
    7.                 String();  
    8.                 String(const char *const);  
    9.                 String(const String &);  
    10.                 ~String();  
    11.                 char & operator[] (unsigned short offset);  
    12.                 char operator[] (unsigned short offset)const;  
    13.                 String operator+(const String&);  
    14.                 void operator+=(const String&);  
    15.                 String & operator= (const String &);  
    16.                 unsigned short GetLen()const {return itsLen;}  
    17.                 const char * GetString()const {return itsString;}  
    18.         private:  
    19.                 String (unsigned short);  
    20.                 char * itsString;  
    21.                 unsigned short itsLen;  
    22. };  
    23. String::String()  
    24. {  
    25.         itsString = new char[1]; //为什么设置成1,这样会导致内存1bytes无法释放吗?我觉得和itsString = new char没区别,那他为什么要设置成1,这样有什么用?21天学会C++那本书,我也有 ,书上也确实是设置成1.  
    26.         itsString[0] = ‘/0‘;  
    27.         itsLen=0;  
    28. }  
    29. String::String(unsigned short len)  
    30. {  
    31.         itsString = new char[len+1];  
    32.         for (unsigned short i =0;i<=len;i++)  
    33.                 itsString[i] = ‘/0‘;  
    34.         itsLen=len;  
    35. }  
    36. String::String(const char * const cString)  
    37. {  
    38.         itsLen = strlen(cString);  
    39.         itsString = new char[itsLen+1];  
    40.         for (unsigned short i=0;i<itsLen;i++)  
    41.                 itsString[i] = cString[i];  
    42.         itsString[itsLen] = ‘/0‘;  
    43. }  
    44. String::String(const String & rhs)  
    45. {  
    46.         itsLen = rhs.GetLen();  
    47.         itsString = new char[itsLen+1];  
    48.         for (unsigned short i = 0;i<itsLen;i++)  
    49.                 itsString[i] = rhs[i];  
    50.         itsString[itsLen] = ‘/0‘;  
    51. }  
    52. String::~String()  
    53. {  
    54.         delete [] itsString;  
    55.         itsLen = 0;  
    56. }  
    57. String& String::operator =(const String & rhs)  
    58. {  
    59.         if (this == &rhs)  
    60.                 return *this;  
    61.         delete [] itsString;  
    62.         itsLen=rhs.GetLen();  
    63.         itsString = new char[itsLen+1];  
    64.         for (unsigned short i = 0;i<itsLen;i++)  
    65.                 itsString[i] = rhs[i];  
    66.         itsString[itsLen] = ‘/0‘;  
    67.         return *this;  
    68. }  
    69. char & String::operator [](unsigned short offset) //这个程序这样写,起到了什么用处??和main中的那一个对应?  
    70. {  
    71.         if (offset > itsLen)  
    72.                 return itsString[itsLen-1]; //这个返回itslen-1到底是什么意思?为什么要减去1 ??  
    73.         else  
    74.                 return itsString[offset];  
    75. }  
    76. char String::operator [](unsigned short offset)const  
    77. {  
    78.         if (offset > itsLen)  
    79.                 itsString[itsLen-1];  
    80.         else  
    81.                 return itsString[offset];  
    82. }  
    83. String String::operator +(const String& rhs)  
    84. {  
    85.         unsigned short totalLen = itsLen + rhs.GetLen();  
    86.         String temp(totalLen);  
    87.         unsigned short i;  
    88.         for (i=0;i<itsLen;i++)  
    89.                 temp[i] = itsString[i];  
    90.         for (unsigned short j = 0;j<rhs.GetLen();j++,i++)  
    91.                 temp[i] = rhs[j];  
    92.         temp[totalLen] = ‘/0‘;  
    93.         return temp;  
    94. }  
    95. void String::operator +=(const String& rhs)  
    96. {  
    97.         unsigned short rhsLen = rhs.GetLen();  
    98.         unsigned short totalLen = itsLen + rhsLen;  
    99.         String temp(totalLen);  
    100.         unsigned short i;  
    101.         for (i = 0;i<itsLen;i++)  
    102.                 temp[i] = itsString[i];  
    103.         for (unsigned short j = 0;j<rhs.GetLen();j++,i++)  
    104.                 temp[i] = rhs[i-itsLen];  
    105.         temp[totalLen] = ‘/0‘;  
    106. }  
    107. int main()  
    108. {  
    109.           
    110.         String s1("initial test"); //调用了什么函数?  
    111.         cout<<"S1:/t"<<s1.GetString()<<endl;  
    112.         char *temp ="Hello World";  
    113.         s1 = temp;//调用了什么函数?  
    114.         cout<<"S1:/t"<<s1.GetString()<<endl;  
    115.         char tempTwo[20];  
    116.         strcpy(tempTwo,"; nice to be here!");  
    117.         s1 += tempTwo;  
    118.         cout<<"tempTwo:/t"<<tempTwo<<endl;  
    119.         cout<<"S1:/t"<<s1.GetString()<<endl;  
    120.         cout<<"S1[4]:/t"<<s1[4]<<endl;  
    121.         cout<<"S1[999]:/t"<<s1[999]<<endl;//调用了什么函数?  
    122.         String s2(" Anoter string");//调用了什么函数?  
    123.         String s3;  
    124.         s3 = s1+s2;  
    125.         cout<<"S3:/t" <<s3.GetString()<<endl;  
    126.         String s4;  
    127.         s4 = "Why does this work?";//调用了什么函数?  
    128.         cout<<"S4:/t"<<s4.GetString()<<endl;  
    129.         return 0;  
    130. }  

swap C++用法

标签:

原文地址:http://www.cnblogs.com/zlcxbb/p/4906224.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!