转载地址

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

    template <class T> void swap ( T& a, T& b )
{
T c(a); a=b; b=c;
} 需要构建临时对象,一个拷贝构造,两次赋值操作。 ,针对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 = ; x < sizeof(T); ++x)
{
pObj1[x] ^= pObj2[x];
pObj2[x] ^= pObj1[x];
pObj1[x] ^= pObj2[x];
}
} ,针对内建类型的优化: int, flaot, double 等,甚至重载运算符的用户自定义类型:向量,矩阵,图像等。。。 type a; -- e.g
type b; -- e.g a = a+b ; -- a=,b=
b = a-b ; -- a=,b=
a= a -b ; -- a= ,b= // 无需构造临时变量。使用基本运算操作符。 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. ,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完全一致,只有当当使用了不同分配器才进行字节拷贝。其余情况直接交换控制信息。 测试用例: ,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+];
for (unsigned short i = ;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+];
for (unsigned short i = ;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,这样会导致内存1bytes无法释放吗?我觉得和itsString = new char没区别,那他为什么要设置成1,这样有什么用?21天学会C++那本书,我也有 ,书上也确实是设置成1.
itsString[] = '/0';
itsLen=;
}
String::String(unsigned short len)
{
itsString = new char[len+];
for (unsigned short i =;i<=len;i++)
itsString[i] = '/0';
itsLen=len;
}
String::String(const char * const cString)
{
itsLen = strlen(cString);
itsString = new char[itsLen+];
for (unsigned short i=;i<itsLen;i++)
itsString[i] = cString[i];
itsString[itsLen] = '/0';
}
String::String(const String & rhs)
{
itsLen = rhs.GetLen();
itsString = new char[itsLen+];
for (unsigned short i = ;i<itsLen;i++)
itsString[i] = rhs[i];
itsString[itsLen] = '/0';
}
String::~String()
{
delete [] itsString;
itsLen = ;
}
String& String::operator =(const String & rhs)
{
if (this == &rhs)
return *this;
delete [] itsString;
itsLen=rhs.GetLen();
itsString = new char[itsLen+];
for (unsigned short i = ;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-]; //这个返回itslen-1到底是什么意思?为什么要减去1 ??
else
return itsString[offset];
}
char String::operator [](unsigned short offset)const
{
if (offset > itsLen)
itsString[itsLen-];
else
return itsString[offset];
}
String String::operator +(const String& rhs)
{
unsigned short totalLen = itsLen + rhs.GetLen();
String temp(totalLen);
unsigned short i;
for (i=;i<itsLen;i++)
temp[i] = itsString[i];
for (unsigned short j = ;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 = ;i<itsLen;i++)
temp[i] = itsString[i];
for (unsigned short j = ;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[];
strcpy(tempTwo,"; nice to be here!");
s1 += tempTwo;
cout<<"tempTwo:/t"<<tempTwo<<endl;
cout<<"S1:/t"<<s1.GetString()<<endl;
cout<<"S1[4]:/t"<<s1[]<<endl;
cout<<"S1[999]:/t"<<s1[]<<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 ;
} 参考引用: ,http://www.vbforums.com/showthread.php?t=245517 ,http://www.cplusplus.com/reference/algorithm/swap/ ,http://codeguru.earthweb.com/forum/showthread.php?t=485643 ,http://stackoverflow.com/questions/1998744/benefits-of-a-swap-function ,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 函数的更多相关文章

  1. 关于swap函数传值的问题

    #include <stdio.h> void swap(int * p3,int * p4); int main() {  int a = 9;  int b = 8;  int * p ...

  2. 自己写一个swap函数交换任意两个相同类型元素的值 对空指针的使用 字节大小的判断(二)了解原理

    验证的代码: #include <stdio.h> int main(){ char c = 'z'; ) + (c << ) + () + 'a'; printf(" ...

  3. swap函数的四种写法

    swap 函数的四种写法 (1)经典型 --- 嫁衣法 void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } ( ...

  4. [转]谈谈C++中的swap函数

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

  5. [Effective C++ --025]考虑写出一个不抛异常的swap函数

    引言 在我的上一篇博客中,讲述了swap函数. 原本swap只是STL的一部分,而后成为异常安全性编程的脊柱,以及用来处理自我赋值可能性. 一.swap函数 标准库的swap函数如下: namespa ...

  6. [020]转--C++ swap函数

    原文来自:http://www.cnblogs.com/xloogson/p/3360847.html 1.C++最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符 template < ...

  7. 从Swap函数谈加法溢出问题

    1.      初始题目 面试题:). 这个题目太经典,也太简单,有很多人都会不假思索结出答案: //Code 1 void Swap(int* a, int* b) { *a = *a + *b; ...

  8. EC读书笔记系列之13:条款25 考虑写出一个不抛异常的swap函数

    记住: ★当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定其不抛出异常 ★若你提供一个member swap,也该提供一个non-member swap来调用前者.对于cla ...

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

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

随机推荐

  1. javascritp日期函数总结

    getDate()与getDay()的区别: obj.getDate()返回一个月中的某一天:obj.getDay()返回一个星期中的某一天. getYear()与getFullYear()的区别: ...

  2. PHP变量名区分大小写,函数名不区分大小写

    PHP变量名区分大小写,函数名不区分大小写,经常被新手忽视的小细节,测试如下. PHP变量名区分大小写测试: <?php $aaa = "phpddt.com"; $AAA ...

  3. 删:[CentOS 7] 安装nginx

    下载对应当前系统版本的nginx包(package) # wget  http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-cent ...

  4. IEnumerable 接口 实现foreach 遍历 实例

    额 为啥写着东西? 有次面试去,因为用到的时候特别少 所以没记住, 这个单词 怎么写! 经典的面试题: 能用foreach遍历访问的对象的要求? 答:  该类实现IEnumetable 接口   声明 ...

  5. 10.python中的序列

    本来说完字符串.数字.布尔值之后,应该要继续讲元祖.列表之类的.但是元祖和列表都属于序列,所以有必要先讲讲python的序列是什么. 首先,序列是是Python中最基本的数据结构.序列中的每个元素都分 ...

  6. oracle 几个时间函数探究

    近来经常用到时间函数,在此写一个笔记,记录自己的所得,希望也对您有所帮助. 1.对于一个时间如 sysdate:2015/1/30 14:16:03如何只得到年月日,同时它的数据类型不变化呢? 最容易 ...

  7. 随机数范围扩展(如rand7()到rand10())(转)

    题目:已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10.分析:要保证rand10()在整数1-10的均匀分布,可以构造一个1-10*n的均 ...

  8. IBM MQ扩大队列最大消息长度

    要设置MQ的最大消息长度,需要考虑同时设置队列管理,队列以及通道的最大消息长度. 具体操作如下: runmqsc 队列管理器名称 alter qmgr maxmsgl(10000000) 1 : al ...

  9. C#之玩转反射【转:http://www.cnblogs.com/yaozhenfa/p/CSharp_Reflection_1.html】

    前言 之所以要写这篇关于C#反射的随笔,起因有两个:   第一个是自己开发的网站需要用到   其次就是没看到这方面比较好的文章. 所以下定决心自己写一篇,废话不多说开始进入正题. 前期准备 在VS20 ...

  10. c++性能测试

    程序分析是以某种语言书写的程序为对象,对其内部的运作流程进行分析.程序分析的目的主要有三点:一是通过程序内部各个模块之间的调用关系,整体上把握程序的运行流程,从而更好地理解程序,从中汲取有价值的内容. ...