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> inlinevoid __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 _Rightif (this == &_Right); // same object, do nothingelse if (_Mybase::_Alval == _Right._Alval){ // same allocator, swap control information#if _HAS_ITERATOR_DEBUGGINGthis->_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> inlinevoid swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right){ // swap _Left and _Right vectors_Left.swap(_Right);}void swap(_Myt& _Right){ // exchange contents with _Rightif (this == &_Right); // same object, do nothingelse if (this->_Alval == _Right._Alval){ // same allocator, swap control information#if _HAS_ITERATOR_DEBUGGINGthis->_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 assignsthis->_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);}

记得本科上C++课,老师特别喜欢拿String来举例子,面试题也特别喜欢String。。。下面说说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 abovereturn *this; }

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

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

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

 6. vector clear and swap trick

vector.clear并只是将size变量置为0,并没有及时归还OS,STL仍然持有内存,以便后续push_back。实测如下

vector<int> temp;

此时打开资源管理器,内存如下:


增长vector然后清空:

temp.resize( 1024*1024*20 );    // 80M
temp.clear();

此时资源管理器内存:

clear以后进程兵没有及时将内存归还OS。。。通过swap方法:

 tmp.resize(1024*1024*20);    // 80M// tmp.clear();{std::vector<int>().swap(tmp);        // 将内存归还OS}

退出作用域,临时对象销毁。内存归还OS。此时资源管理器中进程内存回到1,864K。

附上网络版的String:

#include <iostream> #include <cstring> using namespace std; class String {public:String();String(const char *const);String(const String &);~String();char & operator[] (unsigned short offset);char operator[] (unsigned short offset)const;String operator+(const String&);void operator+=(const String&);String & operator= (const String &);unsigned short GetLen()const {return itsLen;}const char * GetString()const {return itsString;}private:String (unsigned short);char * itsString;unsigned short itsLen; }; String::String() {itsString = new char[1]; //为什么设置成1,这样会导致内存1bytes无法释放吗?我觉得和itsString = new char没区别,那他为什么要设置成1,这样有什么用?21天学会C++那本书,我也有 ,书上也确实是设置成1.itsString[0] = '/0';itsLen=0; } String::String(unsigned short len) {itsString = new char[len+1];for (unsigned short i =0;i<=len;i++)itsString[i] = '/0';itsLen=len; } String::String(const char * const cString) {itsLen = strlen(cString);itsString = new char[itsLen+1];for (unsigned short i=0;i<itsLen;i++)itsString[i] = cString[i];itsString[itsLen] = '/0'; } String::String(const String & rhs) {itsLen = rhs.GetLen();itsString = new char[itsLen+1];for (unsigned short i = 0;i<itsLen;i++)itsString[i] = rhs[i];itsString[itsLen] = '/0'; } String::~String() {delete [] itsString;itsLen = 0; } String& String::operator =(const String & rhs) {if (this == &rhs)return *this;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; } char & String::operator [](unsigned short offset) //这个程序这样写,起到了什么用处??和main中的那一个对应? {if (offset > itsLen)return itsString[itsLen-1]; //这个返回itslen-1到底是什么意思?为什么要减去1 ??elsereturn itsString[offset]; } char String::operator [](unsigned short offset)const {if (offset > itsLen)itsString[itsLen-1];elsereturn itsString[offset]; } String String::operator +(const String& rhs) {unsigned short totalLen = itsLen + rhs.GetLen();String temp(totalLen);unsigned short i;for (i=0;i<itsLen;i++)temp[i] = itsString[i];for (unsigned short j = 0;j<rhs.GetLen();j++,i++)temp[i] = rhs[j];temp[totalLen] = '/0';return temp; } void String::operator +=(const String& rhs) {unsigned short rhsLen = rhs.GetLen();unsigned short totalLen = itsLen + rhsLen;String temp(totalLen);unsigned short i;for (i = 0;i<itsLen;i++)temp[i] = itsString[i];for (unsigned short j = 0;j<rhs.GetLen();j++,i++)temp[i] = rhs[i-itsLen];temp[totalLen] = '/0'; } int main() {String s1("initial test"); //调用了什么函数?cout<<"S1:/t"<<s1.GetString()<<endl;char *temp ="Hello World";s1 = temp;//调用了什么函数?cout<<"S1:/t"<<s1.GetString()<<endl;char tempTwo[20];strcpy(tempTwo,"; nice to be here!");s1 += tempTwo;cout<<"tempTwo:/t"<<tempTwo<<endl;cout<<"S1:/t"<<s1.GetString()<<endl;cout<<"S1[4]:/t"<<s1[4]<<endl;cout<<"S1[999]:/t"<<s1[999]<<endl;//调用了什么函数?String s2(" Anoter string");//调用了什么函数?String s3;s3 = s1+s2;cout<<"S3:/t" <<s3.GetString()<<endl;String s4;s4 = "Why does this work?";//调用了什么函数?cout<<"S4:/t"<<s4.GetString()<<endl;return 0; }

参考引用:

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

History:

20140401 - add 6 vector clear and swap trick!

谈谈C++中的swap函数相关推荐

  1. 【转】 谈谈C++中的swap函数

    1,最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符. 1 template <class T> void swap ( T& a, T& b ) 2 { 3 ...

  2. C++中的swap函数

    C++中的swap函数:交换函数 好处:不用担心交换变量精度的缺失,无需构造临时变量,不会增加空间复杂度 swap 包含在命名空间std 里面 swap(a,b);(交换两个数) swap(a[i] ...

  3. C语言中利用Swap函数交换变量a,b

    C语言中利用Swap函数交换变量a,b 常见错误写法 error1 void Sawp_error1(int a,int b) {int tmp;tmp=a;a=b;b=tmp; } int main ...

  4. C++中的swap()函数

    C++中的swap函数:交换函数 好处:不用担心交换变量精度的缺失,无需构造临时变量,不会增加空间复杂度 swap 包含在命名空间std 里面 swap(a,b); swap(a[i] = b[j]) ...

  5. php 匿名函数好处,谈谈PHP中的匿名函数与闭包

    //匿名函数,说白了就是"没有名字的函数",不多说.给一段代码可能更为明白: //例一,定义匿名函数并调用 $str='world'; $func=function ($str) ...

  6. python中实现swap函数

    python中实现swap函数python中实现swap函数python中实现swap函数 Python以引用方式管理对象,你可以交换引用,但通常不能交换内存中的对象值. def swap(a, b) ...

  7. Java中的Swap函数

    在Java中没有直接用于交换的Swap函数,所以需要我们自己写一个用于交换的函数. public static void swap(int [] a,int x,int y)     {        ...

  8. Python中的swap函数

    问:Python中为什么没有swap(a, b)方法?我们在Python中如何交换对象? Python 不使用这种方式(swap(a, b)).Python以引用方式管理对象,你可以交换引用,但通常不 ...

  9. c++语言swap函数,C++中swap函数

    本文是我用到swap函数时,对其产生好奇,所以结合网上有关博文写下的.个人水平有限,若有错误的地方,欢迎留言指出.谢谢! 一.通用的函数交换模板 template void swap(T &a ...

最新文章

  1. 字符串函数用法 php,PHP字符串函数print()的用法
  2. Spark2.0研究
  3. python的open方法_Python os.open() 方法
  4. spark java 计数_spark程序——统计包含字符a或者b的行数
  5. leetcode253. 会议室 II
  6. OSPF:STUB与NSSA区别
  7. 顶点计划 挑战性课程讨论
  8. 【游戏策划】【碎碎念】关于横版跳跃类游戏的关卡设计
  9. 苹果、三星、华为的2019财报三国杀
  10. 图像与视频处理中的优化方法
  11. 简述计算机硬件,简述计算机硬件的组成部分
  12. 多个工作表数据汇总怎么做?
  13. 编程小白学习编程的开始
  14. R语言使用ggplot绘制线型与点
  15. fluent瞬态计算终止条件在哪里设置_Fluent案例11【螺旋桨_MRF回转体】
  16. rocksdb性能mysql_mysql rocksdb使用报告
  17. 数值代数课设(99分)--基于Jacobi迭代,GS迭代,SOR迭代对泊松方程的求解[matlab](上)
  18. 日本自动外币兑换机公司ActPro在两年半时间内占据全球市场份额第一名
  19. 用 Kotlin 开发 Android 项目是一种什么样的感受?(二)
  20. nodejs 实现发邮件nodemailer

热门文章

  1. 1258:数字金字塔
  2. c语言之动静态链接库
  3. 使用JavaScript制作轮播
  4. h3c服务器增加硬盘,H3C服务器硬盘配置Raid
  5. 如何修改安卓软件的图标和名字
  6. python字符串转整数
  7. 阿里云视频点播指定清晰度
  8. 支持tcam的服务器,一种支持TCAM规则更新与压缩方法.doc
  9. pmos低电平驱动_MOS管驱动电路总结
  10. camera中文版软件 ip_911 S5使用教程动态IP代理配置VMlogin中文版反指纹浏览器Multilogin浏览器教程...