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
时间: 2024-11-09 00:56:27

c++ swap 函数的相关文章

《Effective C 》资源管理:条款25--考虑写出一个不抛出异常的swap函数

条款25考虑写出一个不抛出异常的swap函数 条款25:考虑写出一个不抛出异常的swap函数 swap是STL中的标准函数,用于交换两个对象的数值.后来swap成为异常安全编程(exception-safe programming,条款29)的脊柱,也是实现自我赋值(条款11)的一个常见机制.swap的实现如下: namespace std{ template<typename T> void swap(T& a, T& b) { T temp(a); a=b; b=temp;

swap函数的例子

13.31为你的HasPtr类定义一个<运算符,并定义一个HasPtr的vector为这个vector添加一些元素,并对它执行sort.注意何时会调用swap. #include<iostream> #include<string> #include<new> #include<vector> #include<algorithm> using namespace std; class HasPtr { friend void swap(H

条款25:考虑写出一个不抛异常的swap函数

条款25:考虑写出一个不抛异常的swap函数 swap函数在C++中是一个非常重要的函数,但实现也非常复杂. 看一个缺省的std::swap函数的实现 namespace std { template<typename T> void swap( T& a , T& b) { T temp(a); a = b; b = temp } } ①内置类型的调用 int a = 2; int b =3; std::swap(a, b); cout<<"a:&quo

作业二、comp和swap函数

一.swap函数的代码及运行情况 1.代码 1 #include<stdio.h> 2 int main() 3 { 4 void swap(int *m,int *n); 5 int a,b; 6 int *p1,*p2; 7 scanf("%d,%d",&a,&b); 8 p1=&a; 9 p2=&b; 10 swap(p1,p2); 11 printf("%d,%d\n",*p1,*p2); 12 return 0;

关于swap函数传值的问题

#include <stdio.h> void swap(int * p3,int * p4); int main() {  int a = 9;  int b = 8;  int * p1 = &a;  int * p2 = &b;    printf("%x %x\n",p1,p2);  swap(p1,p2);    printf("%d %d\n",a,b);  printf("%d %d\n",*p1,*p2

c/c++和java实现swap函数的不同处

首先我们来看一下在c/c++中实现的swap函数 void swap ( int & a, int & b) { int Temp; temp = a; a = b; b = temp; } 那么在java中是否还能这样呢,很显然java中没有地址引用符号了. 首先我们来看下c/c++和java的区别. 本质区别 C/C++中swap功能的本质:通过传递变量地址(指针或引用)来交换变量地址中的值. Java标榜其中对C/C++一个很大的改进就是:Java对程序员屏蔽了变量地址的概念,减少指

C语言形参与实参的概念及swap函数

形式参数(formal argument)和实际参数(actual argument)是什么? void function(int n); //n为形式参数 int main { int times=5; function(times); //times为实际参数 } void function(int n) { for(int i=0;i<n;i++) printf("hello\n"); } 在声明一个参数时就创建了一个叫形式参数的变量,在上面的例子中形式参数是叫做n的变量.

Effective C++ Item 25 考虑写出一个不抛异常的swap函数

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常 示例: stl里的swap算法 namespace std{ template<typename T> void swap(T &a, T &b){ T temp(a); a = b; b = temp; } } //"pimpl手法"(pointer

Effective C++ 条款25 考虑写出一个不抛出异常的swap函数

1. swap是STL的一部分,后来成为异常安全性编程(exception-safe programming)(见条款29)的一个重要脊柱,标准库的swap函数模板定义类似以下: namespace std{ template<typename T> swap(T& lhs,T& rhs){ T temp(lhs); lhs=rhs; rhs=temp; } } 只要T类型支持拷贝构造以及拷贝赋值,标准库swap函数就会调用T的拷贝构造函数和拷贝构造操作符完成值的转换,但对于某

Effective C++笔记_条款25考虑写出一个不抛出异常的swap函数

1 // lib中的swap 2 namespace std { 3 template<typename T> 4 void swap (T& a, T& b) 5 { 6 T temp(a); 7 a = b; 8 b = temp; 9 } 10 } 11 12 // 缺点:需要赋值大量的数据,但是有的时候并不要复制如此多的内容 13 class WidgetImpl { 14 public: 15 //... 16 private: 17 int a, b, c; 18