[020]转--C++ swap函数
原文来自:http://www.cnblogs.com/xloogson/p/3360847.html
1.C++最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符
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 = ; x < sizeof(T); ++x)
{
pObj1[x] ^= pObj2[x];
pObj2[x] ^= pObj1[x];
pObj1[x] ^= pObj2[x];
}
}
可以省下拷贝构造的过程。
3.针对内建类型的优化: int, float, double 等,甚至重载运算符的用户自定义类型:向量,矩阵,图像等。。。
template <class T> void swap ( T& a, T& b )
{
a = a + b;
b = a - b;
a = a - b;
}
// 无需构造临时变量。使用基本运算操作符。
4.swap的一些特化:std::string, std::vector各自实现了swap函数
string:
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:
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函数,而不是赋值操作符。
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函数。
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);
}
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.
[020]转--C++ swap函数的更多相关文章
- 关于swap函数传值的问题
#include <stdio.h> void swap(int * p3,int * p4); int main() { int a = 9; int b = 8; int * p ...
- 自己写一个swap函数交换任意两个相同类型元素的值 对空指针的使用 字节大小的判断(二)了解原理
验证的代码: #include <stdio.h> int main(){ char c = 'z'; ) + (c << ) + () + 'a'; printf(" ...
- swap函数的四种写法
swap 函数的四种写法 (1)经典型 --- 嫁衣法 void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } ( ...
- c++ swap 函数
转载地址 1,最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符. template <class T> void swap ( T& a, T& b ) { T ...
- [转]谈谈C++中的swap函数
1,最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符. template <class T> void swap ( T& a, T& b ) { T c(a) ...
- [Effective C++ --025]考虑写出一个不抛异常的swap函数
引言 在我的上一篇博客中,讲述了swap函数. 原本swap只是STL的一部分,而后成为异常安全性编程的脊柱,以及用来处理自我赋值可能性. 一.swap函数 标准库的swap函数如下: namespa ...
- 从Swap函数谈加法溢出问题
1. 初始题目 面试题:). 这个题目太经典,也太简单,有很多人都会不假思索结出答案: //Code 1 void Swap(int* a, int* b) { *a = *a + *b; ...
- EC读书笔记系列之13:条款25 考虑写出一个不抛异常的swap函数
记住: ★当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定其不抛出异常 ★若你提供一个member swap,也该提供一个non-member swap来调用前者.对于cla ...
- 【转】 谈谈C++中的swap函数
1,最通用的模板交换函数模式:创建临时对象,调用对象的赋值操作符. template <class T> void swap ( T& a, T& b ) { T c(a) ...
随机推荐
- 逻辑回归损失函数(cost function)
逻辑回归模型预估的是样本属于某个分类的概率,其损失函数(Cost Function)可以像线型回归那样,以均方差来表示:也可以用对数.概率等方法.损失函数本质上是衡量”模型预估值“到“实际值”的距离, ...
- iOS开发之UILabel
UILabel是iOS开发中常用的一个组件,主要用来显示内容. UILabel的主要使用如下: /*尺寸*/ CGRect labelRect = CGRectMake(100, 100, 80, 4 ...
- 解读四大移动web应用开发框架真相
[51CTO译文]近来关于新的移动网页框架及移动平台存在不少争论.平心而论,这些工具在条款内容方面的混乱与模糊也是造成大家误解的原因之一.我希望通过几条简短的评述来尽量清理这种认识层面上的混乱状态. ...
- NOIP2003 传染病控制
题四 传染病控制 [问题背景] 近来,一种新的传染病肆虐全球.蓬莱国也发现了零星感染者,为防止该病在蓬莱国 大范围流行,该国政府决定不惜一切代价控制传染病的蔓延.不幸的是,由于人们尚未完 全认 ...
- Ubuntu安装JDK1.6
1.下载JDK 网址: http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-4 ...
- ListView自定义适配器--10.17
1. 添加button 2. ViewHolder 优化性能 就是一个持有者的类,他里面一般没有方法,只有属性,作用就是一个临时的储存器,把你getView方法中每次返回的View存起来,可以下次再用 ...
- linux内存负载分析
衡量内存负载的一个很重要的指标就是页面置换的频率.当linux系统频繁的对页进行换进换出 的时候,说明物理内存不过,不得不进行频繁的置换页面. 使用vmstat(virtual memory stat ...
- 【现代程序设计】【Homework-01】
1维的最大子数组之和 对于1维的最大子数组之和 假设f[i]表示:对于1..i这个序列中,包含i这个元素的最大序列的值 则对于f[i],0<i<=n; 应该有 f[i]=max(a[i], ...
- Spring配置MyBatis
1.MyBatis配置文件(mybatis-config) <?xml version="1.0" encoding="UTF-8"?> <! ...
- android中setOnClickListener的那点事
最近在写代码中,发现在xml文件设置了android:clickable="false",之后这个View还是可点的. 后来发现,是代码中对View设置了监听事件(setOnCli ...