C++String深浅拷贝

来源:互联网 发布:ubuntu 16.04 编辑:程序博客网 时间:2024/04/30 00:28

C++的一个类里面有6个默认成员函数,意味着如果我们自己不定义这六个函数,那么编译器会使用系统的成员函数,但是一旦我们自己定义了这六个成员函数,那么编译器会调用我们定义的,而不是系统默认的,现在我们主要来分析以下String的深浅拷贝问题。深浅拷贝是C++中比较重要的。

什么是浅拷贝

所谓的浅拷贝,就是只拷贝指针指向的内容,而不改变它的地址空间,这就意味着改变其中一个的内容,另一个也跟着改变。
示例:

class String{public:    String(char *str='\0') //构造函数    {        _str = new char[strlen(str)+1];        strcpy(_str, str);    }    String& operator=(const String& s);    ~String()    {        if(_str)        {            delete[]_str;            _str = NULL;        }    }private:    char *_str;};

这里解释一下为什么构造函数缺省传参不传NULL而是‘\0’,其实想一下就知道了,如果我们传NULL,在后面的拷贝构造函数中难免用到它,一旦我们传了一个空指针过去,那么在这里就会出错,因此我们缺省传参传‘\0’,因为C中字符串以\0结尾,这里为了兼容C,因此传参传了一个\0。

我们看看浅拷贝的情况:

void Test(){    String s1("hello world");    String s2(s1);}

通过调试看看他们的存储情况
这里写图片描述
通过调试我们可以看到他们的内存位置,内容都是相同的,改变其中一个另一个也会随之改变,这就是浅拷贝。浅拷贝在我们析构的时候会带来很多问题,因为在一个对象生命周期结束之后就会调用析构函数,因此这就会导致内存泄露等问题,因此我们有了深拷贝。

深拷贝问题

深拷贝,就是拷贝的时候会另外申请一块空间,然后拷贝内容,对其中一块空间进行操作不会影响另一块空间。

深拷贝我们有两种方法:
(1)传统方法:老老实实进行申请空间,然后拷贝。
(2)现代方法:简单来说就是拿来主义,在别人开辟好空间,拷贝好数据,然后我们只需要拿过来就可以了。

(1)传统方法:

String& String::operator=(const String& s){    if_str != s._str)    {        delete []_str;  //释放原空间        _str = new char[strlen(s._str)+1];//申请内存        strcpy(_str, s._str);//拷贝    }        return *this;}

(2)现代方法:

//拷贝构造String(const String& s):_str(NULL)  //思考一下为什么需要初始化为NULL??{    String tmp(s);    swap(_str, tmp._str);}//赋值运算符重载String& String::operator=(String s){    if(_str != s.str)    {        String tmp(s);  //创建一个临时变量进行拷贝        swap(_str, tmp._str);// 交换数据     }return *this;}

思考:
为什么需要在拷贝构造的时候初始化_str为NULL,而重载不需要?
因为创建的tmp为临时空间,出了作用域后会被销毁,销毁后_str为野指针1,这是会导致最后的析构出错,因此需要赋初值为NULL。
在重载的时候创建的tmp也是一个临时变量,出了作用域后会调用析构函数,因为我们本来的意愿就是要释放这块空间,因此我们不用初始化。

现代方法与传统方法比较

现代方法更加简洁,在我们使用的时候通常两种配合着使用。

原创粉丝点击