转载地址

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. jQuery中$(function() {});问题详解

    $(function() {});是$(document).ready(function(){ })的简写,最早接触的时候也说$(document).ready(function(){ })这个函数是 ...

  2. Run JavaScript on your PeopleSoft pages conditionally

    Here, PeopleCode sets the logic that determines when the JavaScript code will run. This is not as si ...

  3. SQL SERVER连接字符串学习

    在使用connection string时遇到一些问题 字符串如下"Data Source= ******;Initial Catalog=******;Persist Security I ...

  4. Cassandra 数据模型 (基于CQL,解决胖列数量限制及灵活性问题)(1.1及以上版本)

    文中主要交代Cassandra的编程模型及数据结构. 由于Cassandra版本数次更新,网上中文的资料已经有点过时,比较有代表性的比如ebuy那篇文章都已经过时了,于是自己找资料,结合官方博客写一篇 ...

  5. php 显示内存 释放内存

    <?php //这只是个例子,下面的数字取决于你的系统 echo memory_get_usage() . "\n"; // 36640 $a = str_repeat(&q ...

  6. 记录C++学习历程

    从今天开始学习C++,将学习中遇到的问题,以及解决方案记录在这个博客里. 函数 1.C++函数声明(原型) 函数原型跟函数的定义在返回值类型,函数名,参数上必须完全一致. 2.程序的内存区域:全局数据 ...

  7. Bash美化

    首先声明下,这些美化方式都不是我自己想的,而是多个牛人的方法. 第一:简单点 这个方法来自于:http://www.vimer.cn/?p=1554 没有美化前是这样,鼠标光标在很右边: 在.bash ...

  8. 多线程异步加载图片async_pictures

    异步加载图片 目标:在表格中异步加载网络图片 目的: 模拟 SDWebImage 基本功能实现 理解 SDWebImage 的底层实现机制 SDWebImage 是非常著名的网络图片处理框架,目前国内 ...

  9. Linux基础 30分钟GDB调试快速突破

    引言 Linus心灵鸡汤 在*nix开发中有道卡叫gdb调试,不管你怎么搞. 它依然在那丝毫不会松动.今天致敬一个 活着的传奇 Linus Torvalds Unix 始于上个世纪60年代,在70年代 ...

  10. 菜鸟学习Hibernate——配置Hibernate环境

    一.概念. Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库.既然学习Hibernate那么第 ...