[转]谈谈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);
- }
记得本科上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 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.
最后这张方式主要是对C++新特性rvalue的优化,具体参见:http://en.wikibooks.org/wiki/More_C++_Idioms/Copy-and-swap
附上网络版的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 ??
- else
- return itsString[offset];
- }
- char String::operator [](unsigned short offset)const
- {
- if (offset > itsLen)
- itsString[itsLen-1];
- else
- return 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
[转]谈谈C++中的swap函数的更多相关文章
- 【转】 谈谈C++中的swap函数
1,最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符. template <class T> void swap ( T& a, T& b ) { T c(a) ...
- 谈谈JS中的高级函数
博客原文地址:Claiyre的个人博客如需转载,请在文章开头注明原文地址 在JavaScript中,函数的功能十分强大.它们是第一类对象,也可以作为另一个对象的方法,还可以作为参数传入另一个函数,不仅 ...
- C++中的swap函数
最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符 template <class T> void swap ( T& a, T& b ) { T c(a); a ...
- 从Swap函数谈加法溢出问题
1. 初始题目 面试题:). 这个题目太经典,也太简单,有很多人都会不假思索结出答案: //Code 1 void Swap(int* a, int* b) { *a = *a + *b; ...
- 考虑写一个不抛出异常的swap函数
我们可以调用std下的swap函数,这是一个模板函数:既可以: ; ; std::swap(a,b); cout<<"a = "<<a<<&qu ...
- C++中swap函数
本文是我用到swap函数时,对其产生好奇,所以结合网上有关博文写下的.个人水平有限,若有错误的地方,欢迎留言指出.谢谢! 一.通用的函数交换模板 template<class T> voi ...
- C++中的swap(交换函数)
交换两个变量的值很简单. 比如 int a = 1; b = 2; 交换a b的值 这个很简单 很容易想到的是找个中间变量比如 int temp = a; a = b; b = temp; 不需要 ...
- 谈谈javascript中的变量提升还有函数提升
在很多面试题中,经常会看到关于变量提升,还有函数提升的题目,所以我就写一篇自己理解之后的随笔,方便之后的查阅和复习. 首先举个例子 foo();//undefined function foo(){ ...
- 谈谈c++中继承中的虚函数
c++继承中的虚函数 c++是一种面向对象的编程语言的一个很明显的体现就是对继承机制的支持,c++中继承分很多种,按不同的分类有不同分类方法,比如可以按照基类的个数分为多继承和单继承,可以按照访问 ...
随机推荐
- SQLServer触发器的使用
创建: create trigger trigger_name on {table_name view_name} {for After Instead of } [ insert, update,d ...
- (转)RabbitMQ消息队列(六):使用主题进行消息分发
在上篇文章RabbitMQ消息队列(五):Routing 消息路由 中,我们实现了一个简单的日志系统.Consumer可以监听不同severity的log.但是,这也是它之所以叫做简单日志系统的原因, ...
- 10款经典的web前端特效的预览及源码
1.CSS3响应式导航菜单 今天我给大家介绍一下如何使用纯CSS来实现的一个响应式导航菜单,我们使用的是HTML5+CSS3技术,当浏览器窗口变小或者使用手机浏览器访问的时候,原本横条菜单会收缩成一个 ...
- POJ 1459(EK)
这题是学着小媛学姐写的.. #include<cstdio> #include<cstring> #include<iostream> #include<qu ...
- extern 数组
最近比较关注C++对象的Linkage类型,然后今天突然想起extern数组这个奇葩的东西,稍微折腾了一下,顺手写个随笔. 首先在cpp中定义几个数组: ,,,,}; ,,,,}; ,,,,}; 然后 ...
- 《Apache之虚拟主机的配置》——RHEL6.3
1.安装httpd软件包: Yum install httpd 2.启动apache服务: [root@redhat Desktop]# /etc/init.d/httpd start Startin ...
- WIN2003跳出res://C:WINDOWSsystem32mys.dll/mys.hta解决方法
出现这个问题的时候 @echo off 请将以下语句复制到记事本中,另存为后缀为.cmd的文件,并运行.当然在命令行下一句句运行也没问题. echo 正在修复,这个过程可能需要几分钟,请稍候…… ru ...
- WFP: 读取XPS文件或将word、txt文件转化为XPS文件
读取XPS格式文件或将doc,txt文件转化为XPS文件,效果图如下: 1.XAML页面代码: <Window x:Class="WpfWord.MainWindow" ...
- angular这个大梗的学习笔记
angular定义一个模块(module)及控制器(controller)的局部声明方法: var app=angular.module("Myapp",[]); myapp.co ...
- 删除 mysql (rpm)
http://blog.csdn.net/love__coder/article/details/6894566 a)查看系统中是否以rpm包安装的mysql [root@linux ~]# rpm ...