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. String s1("initial test"); //调用了什么函数?
  110. cout<<"S1:/t"<<s1.GetString()<<endl;
  111. char *temp ="Hello World";
  112. s1 = temp;//调用了什么函数?
  113. cout<<"S1:/t"<<s1.GetString()<<endl;
  114. char tempTwo[20];
  115. strcpy(tempTwo,"; nice to be here!");
  116. s1 += tempTwo;
  117. cout<<"tempTwo:/t"<<tempTwo<<endl;
  118. cout<<"S1:/t"<<s1.GetString()<<endl;
  119. cout<<"S1[4]:/t"<<s1[4]<<endl;
  120. cout<<"S1[999]:/t"<<s1[999]<<endl;//调用了什么函数?
  121. String s2(" Anoter string");//调用了什么函数?
  122. String s3;
  123. s3 = s1+s2;
  124. cout<<"S3:/t" <<s3.GetString()<<endl;
  125. String s4;
  126. s4 = "Why does this work?";//调用了什么函数?
  127. cout<<"S4:/t"<<s4.GetString()<<endl;
  128. return 0;
  129. }

参考引用:

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

最新文章

  1. SQL SERVER 监控数据文件增长情况
  2. TypeScript Type Compatibility(类型兼容)
  3. 深入理解javascript原型和闭包(6)——继承
  4. poj3259 bellman——ford Wormholes解绝负权问题
  5. C# 爬虫批量下载文件
  6. 省市区(县)三级联动代码(js 数据源)
  7. [CODEVS3299]有序数组合并求第K大问题
  8. mini2440触摸屏驱动分析
  9. bzoj2004
  10. 【HDOJ】1455 Sticks
  11. 【转】Android 带checkbox的listView 实现多选,全选,反选----解决checkbox错位问题
  12. POJ 1088 滑雪 记忆化优化题解
  13. ASP.Net MVC请求处理流程
  14. Unity中提升像素字体清晰度
  15. 201521123076 《Java程序设计》第10周学习总结
  16. hihoCoder 1051 补提交卡(贪心,枚举)
  17. 《网络是怎样连接的》PDF电子版书籍分享
  18. Spring注解测试
  19. Allegro PCB Design GXL (legacy) 使用slide无法将走线推挤到焊盘的原因
  20. ES6 原始类型 Symbol

热门文章

  1. windows使用技巧
  2. 图解win7中IIS7.0的安装及配置ASP环境
  3. 我的一点关于把WndProc指向类的成员函数的看法
  4. php数组中删除元素之重新索引
  5. iOS开发那些事-iOS应用本地化-文本信息本地化
  6. 使用Struts2 验证框架,验证信息重复多次出现
  7. 20150222&mdash;LINQ to SQL 插入、更新和删除
  8. UI3_CustomUITableViewCell
  9. linux命令后台运行[转]
  10. josephus问题