C++String深浅拷贝

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也是一个临时变量,出了作用域后会调用析构函数,因为我们本来的意愿就是要释放这块空间,因此我们不用初始化。

现代方法与传统方法比较

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值