【足迹C++primer】44、交换操作

交换操作

class   HasPtr
{
    friend void fun2();
    friend void swap(HasPtr&, HasPtr&);
public:
//    HasPtr()=default;
    HasPtr(const string &s=string()):ps(new string(s)), i(0){}
    //对ps指向的string,每个HasPtr对象都有自己的拷贝
    HasPtr(const HasPtr &p):ps(new string(*p.ps)), i(p.i) {}
    HasPtr & operator=(const HasPtr &);
    ~HasPtr() {delete ps;}

private:
    string *ps;
    int     i;
};

类值拷贝赋值运算符

HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
    auto newp=new string(*rhs.ps);      //拷贝底层string
    delete ps;          //释放旧内存
    ps=newp;            //从右侧运算对象拷贝数据到本对象
    i=rhs.i;
    return *this;       //返回本对象
}

void fun1()
{
    HasPtr v1,v2;
    HasPtr temp=v1;     //创建v1的值的一个临时副本
    v1=v2;              //将v2的值赋予v1
    v2=temp;            //将保持的v1的值赋予
}

void fun2()
{
    HasPtr v1,v2;
    string *temp=v1.ps; //为v1.ps中的指针创建一个副本
    v1.ps=v2.ps;        //将v2.ps中的指针赋予v1.ps
    v2.ps=temp;         //将保存的v1.ps的原来的指针赋予v2.ps
}

编写我们自己的swap函数

inline void swap(HasPtr &lhs, HasPtr &rhs)
{
    using std::swap;
    swap(lhs.ps, rhs.ps);   //交换指针,而不是string数据
    swap(lhs.i, rhs.i);     //交换int成员
}

//swap的纯在就是为了优化代码

swap函数应该调用swap,而不是std::swap

class Foo
{
public:
    int h;
};

void swap(Foo &lhs, Foo &rhs)
{
    //错误:这个函数使用了标准库版本的swap,而不是HasPtr版本
    std::swap(lhs.h, rhs.h);
    //交换类型Foo的其他成员
}

编译会通过,且正常运行,但是这里我们显示使用了标准库里面的swap

在赋值运算符中使用swap

class   HasPtr2
{
    friend void fun2();
//    friend void swap(HasPtr2&, HasPtr2&);
public:
//    HasPtr()=default;
    HasPtr2(const string &s=string()):ps(new string(s)), i(0){}
    //对ps指向的string,每个HasPtr对象都有自己的拷贝
    HasPtr2(const HasPtr2 &p):ps(new string(*p.ps)), i(p.i) {}
    HasPtr2 & operator=(HasPtr2 );
    ~HasPtr2() {delete ps;}

private:
    string *ps;
    int     i;
};

定义swap的类通常用swap来定义他们的赋值运算符。

动用了一种拷贝并交技术

<pre name="code" class="cpp">//注意rhs是按值传递的,意味着HasPtr的拷贝构造函数
//将右侧运算对象中的string拷贝到rhs
HasPtr2& HasPtr2::operator=(HasPtr2 rhs)
{
    //交换左侧运算对象和局部变量rhs的内容
    swap(*this, rhs);       //rhs现在指向本对象曾经使用的内存
    return *this;           //rhs被销毁,从而delete了rhs中的指针
}


全代码!!

/**
* 功能:13.3交换操作
* 时间:2014年7月14日09:27:08
* 作者:cutter_point
*/

#include<iostream>
#include<string>

using namespace std;

class   HasPtr
{
    friend void fun2();
    friend void swap(HasPtr&, HasPtr&);
public:
//    HasPtr()=default;
    HasPtr(const string &s=string()):ps(new string(s)), i(0){}
    //对ps指向的string,每个HasPtr对象都有自己的拷贝
    HasPtr(const HasPtr &p):ps(new string(*p.ps)), i(p.i) {}
    HasPtr & operator=(const HasPtr &);
    ~HasPtr() {delete ps;}

private:
    string *ps;
    int     i;
};

/**
类值拷贝赋值运算符
*/
HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
    auto newp=new string(*rhs.ps);      //拷贝底层string
    delete ps;          //释放旧内存
    ps=newp;            //从右侧运算对象拷贝数据到本对象
    i=rhs.i;
    return *this;       //返回本对象
}

void fun1()
{
    HasPtr v1,v2;
    HasPtr temp=v1;     //创建v1的值的一个临时副本
    v1=v2;              //将v2的值赋予v1
    v2=temp;            //将保持的v1的值赋予
}

void fun2()
{
    HasPtr v1,v2;
    string *temp=v1.ps; //为v1.ps中的指针创建一个副本
    v1.ps=v2.ps;        //将v2.ps中的指针赋予v1.ps
    v2.ps=temp;         //将保存的v1.ps的原来的指针赋予v2.ps
}

/**
编写我们自己的swap函数
*/
inline void swap(HasPtr &lhs, HasPtr &rhs)
{
    using std::swap;
    swap(lhs.ps, rhs.ps);   //交换指针,而不是string数据
    swap(lhs.i, rhs.i);     //交换int成员
}

//swap的纯在就是为了优化代码

/**
swap函数应该调用swap,而不是std::swap
*/

class Foo
{
public:
    int h;
};

void swap(Foo &lhs, Foo &rhs)
{
    //错误:这个函数使用了标准库版本的swap,而不是HasPtr版本
    std::swap(lhs.h, rhs.h);
    //交换类型Foo的其他成员
}
/*
编译会通过,且正常运行,但是这里我们显示使用了标准库里面的swap
*/

/**
在赋值运算符中使用swap
*/

class   HasPtr2
{
    friend void fun2();
//    friend void swap(HasPtr2&, HasPtr2&);
public:
//    HasPtr()=default;
    HasPtr2(const string &s=string()):ps(new string(s)), i(0){}
    //对ps指向的string,每个HasPtr对象都有自己的拷贝
    HasPtr2(const HasPtr2 &p):ps(new string(*p.ps)), i(p.i) {}
    HasPtr2 & operator=(HasPtr2 );
    ~HasPtr2() {delete ps;}

private:
    string *ps;
    int     i;
};

/*
定义swap的类通常用swap来定义他们的赋值运算符。
动用了一种拷贝并交技术
*/
//注意rhs是按值传递的,意味着HasPtr的拷贝构造函数
//将右侧运算对象中的string拷贝到rhs
HasPtr2& HasPtr2::operator=(HasPtr2 rhs)
{
    //交换左侧运算对象和局部变量rhs的内容
    swap(*this, rhs);       //rhs现在指向本对象曾经使用的内存
    return *this;           //rhs被销毁,从而delete了rhs中的指针
}

int main()
{
    return 0;
}

PS:i`m so sorry,今天上传的晚了很多,有两个原因:

1、今天不知道为什么这网和我闹矛盾了,老是断网,那是非常不稳定!!

2、还有一个就是今天我搞了两节嘿嘿,所以会有两篇!!!

第二篇花了不少时间呢,不认真看,光扫几眼的话,我估计你们还不知道我在干嘛,嘿嘿!!

【足迹C++primer】44、交换操作

时间: 2024-10-13 12:26:48

【足迹C++primer】44、交换操作的相关文章

【足迹C++primer】38、关联容器操作(2)

关联容器操作(2) map的下标操作 map的下标操作 map和unordered_map容器提供了下标运算符合一个对应的at函数 对于一个map使用下标操作,其行为与数组或vector上的下标操作很不相同: 使用一个不再容器中的关键字作为下标,会添加一个此关键字的元素到map中 map和unordered_map的下标操作 c[k] 返回关键字为k的元素,如果关键字k不再c中,添加一个关键字为k的元素,对其进行值初始化 c.at(k) 访问关键字为k的元素,带参数检测,如果k不再c重那么返回一

【足迹C++primer】28、额外的string操作

额外的string操作 构造string的其他方法 //n, len2, pos2 都是无符号值 string s(cp, n) //s是cp指向的数组中前n个字符的拷贝.此数组至少应该包含n个字符 string s(s2, pos2) //s是string s2从下标pos2开始的字符的拷贝. string s(s2, pos2, len2) //s是s2从pos2开始Len2个字符 const char *cp="Hello World!!!"; //以空字符结束的数组 char

【足迹C++primer】26、顺序容器操作

顺序容器操作 向顺序容器添加元素 forward_list //有自己专有版本的insert和emplace: forward_list //不支持push_back和emplace_back vector, string //不支持push_front和emplace_front c.push_back(t), c.emplace_back(args) //在c的尾部创建一个值为t的或者由args创建的元素,返回void c.push_front(t), c.emplace_back(args

【足迹C++primer】38、关联容器操作(1)

关联容器操作 关联容器中还定义了三个类型,如下: set<string>::value_type v1; //这个v1是string类型 set<string>::key_type v2; //这个v2是string类型 map<string, int>::value_type v3; //v3是pair类型pair<const string, int> map<string, int>::key_type v4; //v4是string类型 m

【足迹C++primer】32、定制操作_1

定制操作 向算法传递函数 用 sort 接受第三个参数!! 谓词 bool isShorter(const string &s1, const string &s2) { return s1.size()<s2.size(); } int main() { //按长度由短至长排序words sort(words.begin(), words.end(), isShorter); } 这个words里面是一个string类型的数组,这个调用会是将words重排,所有长度为3的单词排在长

【足迹C++primer】32、定制操作_2

定制操作_2 完整的biggies 好吧上一章是有点2B了,我的,昨天可能是刚考完心情有点小激动就不想学习了,我错了!! /** * 功能:定制操作 * 时间:2014年6月19日07:32:03 * 作者:cutter_point */ #include<iostream> #include<vector> #include<string> #include<numeric> #include<algorithm> using namespac

【足迹C++primer】22、文件输入输出

文件输入输出 使用文件流对象 创建文件流对象时,我们可以提供文件名(可选).如果提供了一个文件名,则open会自动被调用: ifstream in(ifile); //构造一个ifstream并打开给定文件 ofstream out; //输出文件流未关联到任何文件 用fstream代替iostream& 首先这里有一个头文件和一个定义的文件要使用 Sales_data.h #ifndef SALES_DATA_H_INCLUDED #define SALES_DATA_H_INCLUDED #

【足迹C++primer】47、Moving Objects(1)

Moving Objects(1) * 功能:Moving Objects * 时间:2014年7月17日08:46:45 * 作者:cutter_point */ #include<iostream> #include<string> #include<memory> #include<utility> #include<vector> #include<algorithm> #include<set> #include

【足迹C++primer】表达式求值

表达式求值 /** * 功能:表达式求值(0到9) * 时间:2014年6月15日08:02:31 * 作者:cutter_point */ #include<stdlib.h> #include<stack> #include<iostream> #include<string> using namespace std; stack<int> intStack; //存放数值的栈 stack<char> charStack; //存