string模拟实现的拓展讲解
swap的拓展讲解
在C++库里面,是有一个swap的,在string里面是有两个swap的,所以我们就会很纳闷,为什么会出现三个交换,接下来我们会进行讲解
算法库里面的swap
- 算法库里面的swap是可以完成交换的
- 弊端就是,代价太大
- 原因,算法库里面的swap是一个模版,泛函数编程,如果实现深拷贝就需要创建三次空间,销毁三次空间,所以这里虽然使用起来很爽,但是会使用代价很大
string类里面的swap
- 这里就需要我们了解到,我们是否真的需要交换的时候必须创建空间。显然不是的,其实只需要交换字符串就可以实现,而不是反复的创建空间,销毁空间
- 交换
- 所以字符串可以交换,那么我们完全可以调用C++库里面的交换函数,实现交换
注意:这里是swap这里一定要加上std::swap,这里我们调用的是C++库里面的函数,不然会调用string库里面的函数//类里面的交换 void string::swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); }string类里面的全局swap
- 这里我们重载为友元函数
- 有人就疑问了,既然string里面已经有swap了,为什么还需要一个string的全局swap函数
1,首先我们可能会使用swap函数直接交换string
2,其次对于函数模版来说,写一个重载好的全局友元函数这个就像点外卖,使用函数模版就像去做饭,就像你忙的时候,有一个已经点好的外卖和需要自己做饭你选择哪一个,肯定的直接吃外卖。效果一样,又省时间,点外卖就是类似于写一个全局的函数。
3,所以我们为了使用时候不自己使用函数模版,往往是自己实现一个全局swap函数,并且重载为友元函数- 这里我们实现代码的时候可以直接使用复用,从而实现s1,s2的交换
//string全局的交换 void swap(string& s1, string& s2) { s1.swap(s2); }
拷贝构造的拓展讲解
实现拷贝构造是有点麻烦的,所以我们还有一种拷贝构造的写法,那就是可以直接实现构造再拷贝,这里是基于swap的逻辑进一步实现的
代码
//拷贝构造的实现,新版本的实现 string::string(const string& s) { string tmp(s._str); swap(tmp); }代码解释:
- 拷贝构造也是属于构造的一种
![]()
- 首先我们传参过来的是引用并且是利用const修施过的,首先保证了不会被更改
- 我们使用构造函数,构造一个传参过来的string里面的字符
- 然后因为创建的对象是临时对象,所以出去作用域会进行销毁,这里我们不需要担心销毁的问题,所以我们可以放心进行交换
- 我们交换的时候是this和tmp进行交换,调用的是刚才我们写的函数
赋值的拓展讲解
赋值的实现我们可以基于swap和拷贝构造进行实现,但是和拷贝构造还有点不一样,可以进一步进行简化
//赋值,新版本的实现 //string& string::operator=(const string& s) //{ // string tmp(s._str); // swap(tmp); // return *this; //} //这个是使用是需要在初始化的时候去_str=nullptr;不然交换之后会导致s指向的是空的空间,会导致析构失败 string& string::operator=(string s) { swap(s); return *this; }代码的讲解
- 如果我们实现第一种方式还好说,在私有成员变量可以不进行赋值,但是第二个我们必须在初始化成员变量的时候进行赋值
- 首先我们在拷贝构造的另类实现方式里面使用的是引用传参,这里我们直接使用传值传参
- 传值传参会调用拷贝构造,也就是 string& string::operator=(string s)在传递过来的时候,(string s)会调用拷贝构造,那么此时拷贝构造会再拷贝出来一个临时对象作为等一下交换的对象
- 此时问题出现了,这个拷贝构造出现的对象指向的空间是没有的,是不指向空间的,和swap交换空间地址之后,此时(string s)创建的又是一个临时对象,那么出去作用域会进行销毁,所以就会导致销毁的空间是一个指向什么都没有的空间,是不指向地址的
- 解决办法,我们需要对私有变量进行初始化,不然在这里会报错








442

被折叠的 条评论
为什么被折叠?



