1,最通用的模板交換函數模式:建立臨時對象,調用對象的賦值操作符。
template <class T> void swap ( T& a, T& b )<br />{<br /> T c(a); a=b; b=c;<br />}
需要構建臨時對象,一個拷貝構造,兩次賦值操作。
2,針對int型最佳化:
void swap(int & __restrict a, int & __restrict b)<br />{<br />a ^= b;<br />b ^= a;<br />a ^= b;<br />}<br />
無需構造臨時對象,異或
因為指標是int,所以基於這個思路可以最佳化1:
template <typename T> void Swap(T & obj1,T & obj2)<br />{<br /> unsigned char * pObj1 = reinterpret_cast<unsigned char *>(&obj1);<br /> unsigned char * pObj2 = reinterpret_cast<unsigned char *>(&obj2);<br /> for (unsigned long x = 0; x < sizeof(T); ++x)<br /> {<br /> pObj1[x] ^= pObj2[x];<br /> pObj2[x] ^= pObj1[x];<br /> pObj1[x] ^= pObj2[x];<br /> }<br />}
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.<br />a = a + b;<br />b = a - b;<br />a = a - b;<br />Let's introduce new names<br />c = a + b;<br />d = c - b;<br />e = c - d;<br />And we want to prove that d == a and e == b.<br />d = (a + b) - b = a, proved.<br />e = (a + b) - ((a + b) - b) = (a + b) - a = b, proved.<br />For all real numbers.<br />
4,swap的一些特化:
std::string, std::vector各自實現了swap函數,
string中
template<class _Elem,<br />class _Traits,<br />class _Alloc> inline<br />void __CLRCALL_OR_CDECL swap(basic_string<_Elem, _Traits, _Alloc>& _Left,<br />basic_string<_Elem, _Traits, _Alloc>& _Right)<br />{// swap _Left and _Right strings<br />_Left.swap(_Right);<br />}<br />void __CLR_OR_THIS_CALL swap(_Myt& _Right)<br />{// exchange contents with _Right<br />if (this == &_Right)<br />;// same object, do nothing<br />else if (_Mybase::_Alval == _Right._Alval)<br />{// same allocator, swap control information<br /> #if _HAS_ITERATOR_DEBUGGING<br />this->_Swap_all(_Right);<br /> #endif /* _HAS_ITERATOR_DEBUGGING */<br />_Bxty _Tbx = _Bx;<br />_Bx = _Right._Bx, _Right._Bx = _Tbx;<br />size_type _Tlen = _Mysize;<br />_Mysize = _Right._Mysize, _Right._Mysize = _Tlen;<br />size_type _Tres = _Myres;<br />_Myres = _Right._Myres, _Right._Myres = _Tres;<br />}<br />else<br />{// different allocator, do multiple assigns<br />_Myt _Tmp = *this;<br />*this = _Right;<br />_Right = _Tmp;<br />}<br />}
第二個swap(Right)進行判斷,如果使用了相同的分配器,則直接交換控制資訊,否則調用string::operator=進行拷貝賦值。。。所以建議優先使用swap函數,而不是賦值操作符。
vector中
template<class _Ty,<br />class _Alloc> inline<br />void swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right)<br />{// swap _Left and _Right vectors<br />_Left.swap(_Right);<br />}<br />void swap(_Myt& _Right)<br />{// exchange contents with _Right<br />if (this == &_Right)<br />;// same object, do nothing<br />else if (this->_Alval == _Right._Alval)<br />{// same allocator, swap control information<br /> #if _HAS_ITERATOR_DEBUGGING<br />this->_Swap_all(_Right);<br /> #endif /* _HAS_ITERATOR_DEBUGGING */<br />this->_Swap_aux(_Right);<br />_STD swap(_Myfirst, _Right._Myfirst);<br />_STD swap(_Mylast, _Right._Mylast);<br />_STD swap(_Myend, _Right._Myend);<br />}<br />else<br />{// different allocator, do multiple assigns<br />this->_Swap_aux(_Right);<br />_Myt _Ts = *this;<br />*this = _Right;<br />_Right = _Ts;<br />}<br />}<br />
vector的swap原理跟string完全一致,只有噹噹使用了不同分配器才進行位元組拷貝。其餘情況直接交換控制資訊。
測試案例:
5,Copy and Swap idiom
目的:C++異常有三個層級:基本,強,沒有異常。通過建立臨時對象然後交換,能夠實現重載賦值操作符的強異常安全的執行。
Loki中智能指標 臨時變數跟this交換,臨時變數自動銷毀~
SmartPtr& operator=(SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs)<br /> {<br /> SmartPtr temp(rhs);<br /> temp.Swap(*this);<br /> return *this;<br /> }
boost::share_ptr,share_ptr定義了自己的swap函數。
shared_ptr & operator=( shared_ptr const & r ) // never throws<br /> {<br /> this_type(r).swap(*this);<br /> return *this;<br /> }<br /> void swap(shared_ptr<T> & other) // never throws<br /> {<br /> std::swap(px, other.px);<br /> pn.swap(other.pn);<br /> }
記得本科上C++課,老師特別喜歡拿String來舉例子,面試題也特別喜歡String。。。下面說說String::opreator=函數的最佳化:
最一般的寫法,特點:使用const string& 傳參防止臨時對象。
String& String::operator =(const String & rhs)<br />{<br />if (itsString)<br />delete [] itsString;<br />itsLen = rhs.GetLen();<br />itsString = new char[itsLen+1];<br />for (unsigned short i = 0;i<itsLen;i++)<br />itsString[i] = rhs[i];<br />itsString[itsLen] = '/0';<br />return *this;<br />}
最佳化1,防止自我間接賦值,a = b; c = b; a = c; 如果沒有第一個if判斷,當把c賦給a的時候,刪除了a.itsString,後面的拷貝就會出錯。注意是if(this==&rhs), 而不是if(*this==rhs) .
String& String::operator =(const String & rhs)<br />{<br />if (this == &rhs)<br />return *this;<br />if (itsString)<br />delete [] itsString;<br />itsLen=rhs.GetLen();<br />itsString = new char[itsLen+1];<br />for (unsigned short i = 0;i<itsLen;i++)<br />itsString[i] = rhs[i];<br />itsString[itsLen] = '/0';<br />return *this;<br />}
最佳化2,不進行拷貝賦值,只是交換控制資訊,而且是強異常安全:
String & String::operator = (String const &rhs)<br />{<br />if (this != &rhs)<br />String(rhs).swap (*this); // Copy-constructor and non-throwing swap<br />// Old resources are released with the destruction of the temporary above<br />return *this;<br />}
最佳化3,以最原始的傳值方式傳參,避免臨時對象建立:
String & operator = (String s) // the pass-by-value parameter serves as a temporary<br />{<br /> s.swap (*this); // Non-throwing swap<br /> return *this;<br />}// Old resources released when destructor of s is called.
最後這張方式主要是對C++新特性rvalue的最佳化,具體參見:http://en.wikibooks.org/wiki/More_C++_Idioms/Copy-and-swap
附上網路版的String:
#include <iostream><br />#include <cstring><br />using namespace std;<br />class String<br />{<br /> public:<br /> String();<br /> String(const char *const);<br /> String(const String &);<br /> ~String();<br /> char & operator[] (unsigned short offset);<br /> char operator[] (unsigned short offset)const;<br /> String operator+(const String&);<br /> void operator+=(const String&);<br /> String & operator= (const String &);<br /> unsigned short GetLen()const {return itsLen;}<br /> const char * GetString()const {return itsString;}<br /> private:<br /> String (unsigned short);<br /> char * itsString;<br /> unsigned short itsLen;<br />};<br />String::String()<br />{<br /> itsString = new char[1]; //為什麼設定成1,這樣會導致記憶體1bytes無法釋放嗎?我覺得和itsString = new char沒區別,那他為什麼要設定成1,這樣有什麼用?21天學會C++那本書,我也有 ,書上也確實是設定成1.<br /> itsString[0] = '/0';<br /> itsLen=0;<br />}<br />String::String(unsigned short len)<br />{<br /> itsString = new char[len+1];<br /> for (unsigned short i =0;i<=len;i++)<br /> itsString[i] = '/0';<br /> itsLen=len;<br />}<br />String::String(const char * const cString)<br />{<br /> itsLen = strlen(cString);<br /> itsString = new char[itsLen+1];<br /> for (unsigned short i=0;i<itsLen;i++)<br /> itsString[i] = cString[i];<br /> itsString[itsLen] = '/0';<br />}<br />String::String(const String & rhs)<br />{<br /> itsLen = rhs.GetLen();<br /> itsString = new char[itsLen+1];<br /> for (unsigned short i = 0;i<itsLen;i++)<br /> itsString[i] = rhs[i];<br /> itsString[itsLen] = '/0';<br />}<br />String::~String()<br />{<br /> delete [] itsString;<br /> itsLen = 0;<br />}<br />String& String::operator =(const String & rhs)<br />{<br /> if (this == &rhs)<br /> return *this;<br /> delete [] itsString;<br /> itsLen=rhs.GetLen();<br /> itsString = new char[itsLen+1];<br /> for (unsigned short i = 0;i<itsLen;i++)<br /> itsString[i] = rhs[i];<br /> itsString[itsLen] = '/0';<br /> return *this;<br />}<br />char & String::operator [](unsigned short offset) //這個程式這樣寫,起到了什麼用處??和main中的那一個對應?<br />{<br /> if (offset > itsLen)<br /> return itsString[itsLen-1]; //這個返回itslen-1到底是什麼意思?為什麼要減去1 ??<br /> else<br /> return itsString[offset];<br />}<br />char String::operator [](unsigned short offset)const<br />{<br /> if (offset > itsLen)<br /> itsString[itsLen-1];<br /> else<br /> return itsString[offset];<br />}<br />String String::operator +(const String& rhs)<br />{<br /> unsigned short totalLen = itsLen + rhs.GetLen();<br /> String temp(totalLen);<br /> unsigned short i;<br /> for (i=0;i<itsLen;i++)<br /> temp[i] = itsString[i];<br /> for (unsigned short j = 0;j<rhs.GetLen();j++,i++)<br /> temp[i] = rhs[j];<br /> temp[totalLen] = '/0';<br /> return temp;<br />}<br />void String::operator +=(const String& rhs)<br />{<br /> unsigned short rhsLen = rhs.GetLen();<br /> unsigned short totalLen = itsLen + rhsLen;<br /> String temp(totalLen);<br /> unsigned short i;<br /> for (i = 0;i<itsLen;i++)<br /> temp[i] = itsString[i];<br /> for (unsigned short j = 0;j<rhs.GetLen();j++,i++)<br /> temp[i] = rhs[i-itsLen];<br /> temp[totalLen] = '/0';<br />}<br />int main()<br />{</p><p> String s1("initial test"); //調用了什麼函數?<br /> cout<<"S1:/t"<<s1.GetString()<<endl;<br /> char *temp ="Hello World";<br /> s1 = temp;//調用了什麼函數?<br /> cout<<"S1:/t"<<s1.GetString()<<endl;<br /> char tempTwo[20];<br /> strcpy(tempTwo,"; nice to be here!");<br /> s1 += tempTwo;<br /> cout<<"tempTwo:/t"<<tempTwo<<endl;<br /> cout<<"S1:/t"<<s1.GetString()<<endl;<br /> cout<<"S1[4]:/t"<<s1[4]<<endl;<br /> cout<<"S1[999]:/t"<<s1[999]<<endl;//調用了什麼函數?<br /> String s2(" Anoter string");//調用了什麼函數?<br /> String s3;<br /> s3 = s1+s2;<br /> cout<<"S3:/t" <<s3.GetString()<<endl;<br /> String s4;<br /> s4 = "Why does this work?";//調用了什麼函數?<br /> cout<<"S4:/t"<<s4.GetString()<<endl;<br /> return 0;<br />}
參考引用:
1,http://www.vbforums.com/showthread.php?t=245517
2,http://www.cplusplus.com/reference/algorithm/swap/
3,http://codeguru.earthweb.com/forum/showthread.php?t=485643
4,http://stackoverflow.com/questions/1998744/benefits-of-a-swap-function
5,http://answers.google.com/answers/threadview/id/251027.html
C++ idioms
http://en.wikibooks.org/wiki/Category:More_C%2B%2B_Idioms
Copy and Swap idiom
http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom