博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++Primer 交换操作
阅读量:2433 次
发布时间:2019-05-10

本文共 3240 字,大约阅读时间需要 10 分钟。

除了定义拷贝控制成员,管理资源的类通常还定义了一个名为swap的函数。为了交换两个对象我们需要进行一次拷贝和两次赋值。

HasPtr temp = v1;    //创建v1的值的一个临时副本v1 = v2;    //将v2的值赋予v1()v2 = temp;    //将保存的v1的值赋予v2

拷贝一个类值的HasPtr会分配一个新string并将其拷贝到HasPtr指向的位置,而这些拷贝中的内存分配都是不必要的。我们更希望swap交换指针,而不是分配string的新副本

string *temp = v1.ps;   //为v1.ps中的指针创建一个副本v1.ps = v2.ps;         //将v2.ps中的指针赋予v1.psv2.ps = temp;          //将保存的v1.ps中原来的指针赋予v2.ps

编写自己的swap函数

class HasPtr{
friend void swap(HasPtr&, HasPtr&);};inline swap(HasPtr &lhs, HasPtr &rhs){
using std::swap; swap(lhs.ps, rhs.ps); swap(lhs.i, rhs.i);}

如果一个类成员有自己的swap函数版本,就不能调用标准库的std::swap(),应该直接调用类型特定的swap函数

在赋值运算中使用swap
定义了swap函数的类,通常用swap来定义它们的赋值运算符,这些运算符使用了一种名为拷贝并交换(copy and swap)的技术。这种技术将左侧运算对象与右侧对象的一个副本进行交换:

//注意rhs是按值传递的,意味着HasPtr的拷贝构造函数将右侧运算对象中的string拷贝到rhsHasPtr& HasPtr::operator=(HasPtr rhs){
//交换左侧运算对象和局部变量rhs的内容 swap(*this, rhs); return *this;}

该版本中,并非是引用传递,而是值传递,rhs是右侧运算对象的一个副本,参数传递时拷贝HasPtr的操作会分配该对象string的一个新副本。

在swap调用之后,*this中的指针成员指向新分配的string——右侧运算对象中string的一个副本。当赋值运算符结束时,rhs被销毁,HasPtr中的析构函数被执行。此析构函数delete rhs现在指向的内存,即,释放掉左侧运算对象中原来的内存。
这个技术自动处理了自赋值的情况,它通过在改变左侧运算对象之前拷贝右侧对象保证了字赋值的正确。

解释:swap(HasPtr&, HasPtr&)中对swap的调用不会导致递归循环

解答:在swap函数中又调用了swap来交换ps和i,但这两个类型为指针和整型,属于内置类型。因此函数调用中的swap调用被解析为std::swap,而不是HasPtr特定版本的swap函数,所以不会导致递归调用。

为你的类值版本的HasPtr类编写swap函数

inline void swap(HasPtr &lhs, HasPtr &rhs){
cout << " 交换 " << *lhs.ps << " 和 " << *rhs.ps << endl; swap(lhs.ps, rhs.ps); //交换指针 swap(lhs.i, rhs.i); //交换int成员 }

为你的HasPtr类定义一个<运算符,并定义一个HasPtr的vector。为这个vector添加一些元素,并对它执行sort。注意何时会调用swap

<运算符直接返回两个HasPtr的ps指向的string的比较结果即可,但需要注意的是,它应该被声明为const。

#include 
#include
#include
#include
using namespace std;class HasPtr {
friend void swap(HasPtr&, HasPtr&);public: HasPtr(const string &s = string()):ps(new string(s)),i(0){
} //默认构造函数 HasPtr(const HasPtr& p):ps(new string(*p.ps)), i(p.i) {
} //拷贝构造函数 HasPtr& operator=(const HasPtr&); //拷贝赋值运算符 HasPtr& operator=(const string&); //赋予新string string& operator*(); //解引用 bool operator<(const HasPtr&) const; //比较运算 ~HasPtr(); //析构函数private: string* ps; int i;};HasPtr::~HasPtr() {
delete ps; //释放string的内存}inline HasPtr& HasPtr::operator=(const HasPtr & rhs) {
auto newps = new string(*rhs.ps); //拷贝指针指向的对象 delete ps; //销毁原string ps = newps; //指向新的string i = rhs.i; //使用内置的int赋值 return *this; //返回此对象的引用}HasPtr& HasPtr::operator=(const string& rhs) {
*ps = rhs; return *this;}string& HasPtr::operator*() {
return *ps;}inline void swap(HasPtr& lhs, HasPtr& rhs) {
using std::swap; cout << " 交换 " << *lhs.ps << " 和 " << *rhs.ps << endl; swap(lhs.ps, rhs.ps); //交换指针 swap(lhs.i, rhs.i); //交换int成员 }bool HasPtr::operator<(const HasPtr& rhs) const {
return *ps < *rhs.ps;}int main() {
vector
v; int n = atoi(__argv[1]); for (int i = 0; i < n; i++) v.push_back(to_string(n - i)); for (auto p : v) {
cout << *p << " "; } cout << endl; sort(v.begin(), v.end()); for (auto p : v) {
cout << *p << " "; } cout << endl; return 0;}

类指针的HasPtr版本会从swap函数中受益吗?

默认的swap版本简单交换两个对象的非静态成员,对于HasPtr来言,就是交换string指针ps、引用计数指针use和整型值i。因此,默认的swap版本能够正确处理类指针HasPtr的交换,专用swap版本不会有更多受益。

转载地址:http://wtxmb.baihongyu.com/

你可能感兴趣的文章
Hibernate入门与实例
查看>>
Jython入门学习
查看>>
Hiberate基础用法实例
查看>>
Maven编译时指定JDK版本
查看>>
Hibernate单向关联N-1
查看>>
Hibernate单向关联1-1
查看>>
jQuery自定义动画
查看>>
Spring-data-redis在shiro中的实例
查看>>
GUN C中__attribute__作用
查看>>
3、系统调用之SYSCALL_DEFINE分析
查看>>
linux的signal_pending及signal
查看>>
OBJDUMP用法
查看>>
c/cplusplus通用makefile
查看>>
JavaScript-密码强度
查看>>
【SSH】1366-InCorrect string value:'\xE9\x99\x88\xE6\x96\xB0...'for column 'name' at row 1
查看>>
SpringCloud前身之微服务
查看>>
纵览全局——SSH
查看>>
纵览全局——Mybatis
查看>>
PC端-中文转拼音后续问题
查看>>
第七章-面向对象技术
查看>>