赞
踩
string s1("hello world");
string s2(s1);
s2(s1)需要用到拷贝构造函数,大多数情况下,我们写string拷贝构造函数我们会这样写,创建一个新空间后,把内容依次考入。
- string(const string& s)
- {
- _str = new char[s._capacity+1];
- _size = s._size;
- _capacity = s._capacity;
- strcpy(_str, s._str);
- }
现在我们把上面这种写法叫传统写法。 下面是我们的进阶写法。(进阶写法不是为了提高效率,是为了代码更简洁。 )
- string(const string & s)
- {
- string tmp(s._str);//构造函数
- swap(_str, tmp._str);
- swap(_size, tmp._size);
- swap(_capacity, tmp._capacity);
- }
这里面的swap库模板如下。
目前这是个不完善的进阶写法。我们继续往下看。
交换前。
交换后
但是出拷贝构造函数时,tmp要释放,要调用析构函数,此时tmp的_str已经变成和原先this->_str一样的值,然而因为有的编译器不默认把_str设为NULL而是其他随机值的,那么tmp释放,调用析构函数,delete或free释放不是new或malloc等动态开辟的空间的话,就会报错,而delete或free对空指针释放不报错。
所以,为了解决这个问题,我们可以采用先把_str初始化为空的办法。此时tmp和this->_str交换地址后,tmp得到的是NULL,此时析构函数里面的delete或free不会报错。
- string(const string& s)
- ;_str(nullptr)
- , _size(0)
- , _capacity(0)
- {
- string tmp(s._str);//构造函数
- swap(_str, tmp._str);
- swap(_size, tmp._size);
- swap(_capacity, tmp._capacity);
- }
这里面的swap其实也是std命名空间中的库模板。
此时各项值如下。
下面还需要对上面代码进一步优化。
问题:下面两个有什么区别。
第一个
第二个
上面的是一个其实是需要自己在类里面定义一个swap函数。
上面的第二个,其实是类模板,在上述代码中,T被系统识别为string类型,这里面需要进行三次深拷贝。
(一次拷贝构造,两次赋值)
(这部分了解即可)有了模板以后,内置类型必须有构造和析构了。
这两个都是有意义的。
第二个可以认为是调用int的默认构造。如果是int*j 那么j就是空指针。这两个都是因为为了兼容模板所以产生此现象的。
下面是s1.swap(s2)方式代替swap(s1,s2)的方法。
void swap(string& s) { std::swap(_str, s._str); std::swap(_size, tmp._size); std::swap(_capacity, tmp._capacity); }swap前面如果不写std::的话会报错,因为swap会先在局部找,但是在局部类域找到的只有一个参数的swap,所以会报错。加上std,swap就直接在std里面找。
下面是赋值的进阶写法。 和进阶深拷贝有很多相似之处。
- string & = (const string & s)
- {
- if (*this != s)
- {
- string tmp(s);
- swap(tmp);
- }
- return *this
- }
这里面tmp用析构吗?
会析构的,只要定义了局部的对象 出了作用域都要销毁的。
下面string s相当于形参是拷贝构造的,所以可以直接swap进行交换。
- string & = (string s)
- {
- swap(s);
- return *this;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。