string类深拷贝,写时拷贝

在实现string类时不能用简单的浅拷贝去实现,因为浅拷贝会简单让两个对象指向同一块空间,这样的缺陷是两者指向同一块空间,析构时会出现程序崩溃的问题,两个对象管理同一块空间,一改都改,这显然是你所不期待的。
这里写图片描述

所以深拷贝就应运而生,所谓的深拷贝就是在用A对象拷贝B对象时,为B对象开辟与A对象一样大的空间,大家各自管理自己的空间。
这里写图片描述

下面简单的去实现一下深拷贝。

#include<iostream>
#include<cstring>
using namespace std;

class String
{
public:
    String(char* str = "")
        :_str(new char[strlen(str) + 1])
    {
        strcpy(_str, str);
    }

    ~String()
    {
        delete[] _str;
    }

    传统写法
    //String(const String& str)
    //  :_str(new char[strlen(str._str) + 1])
    //{
    //  strcpy(_str, str._str);
    //}
    //String& operator=(const String& str)
    //{
    //  /*if (this != &str)
    //  {
    //      delete[] _str;
    //      _str = new char[strlen(str._str) + 1];
    //      strcpy(_str, str._str);
    //  }
    //  return *this;*/
    //  char* tmp = new char[strlen(str._str) + 1];
    //  strcpy(tmp, str._str);
    //  delete[] _str;
    //  _str = tmp;
    //  return *this;
    //}
    //现代写法
    String(const String& str)
        :_str(NULL)
    {
        String tmp(str._str);
        swap(_str, tmp._str);
    }
    //值传递过来的str是已经创建好的临时空间,这块空间的内容正是我想要的
    String& operator=(String str)
    {
        swap(_str, str._str);
        return *this;
    }
    char* Getstr()
    {
        return _str;
    }
private:
    char* _str;
};

上面呢就是string类的深拷贝,在写深拷贝时提供了现代写法与传统写法,推荐使用现代写法,优势在于效率更高,代码复用性更强,益于管理。

有了深拷贝,这个string类的实现是没有问题的,但是思考一下引入深拷贝,有两方面的原因,一:同一块空间析构多次会出现问题,二:一改多改,与实际需求不否。
现在假设我们已经解决了问题一,(记住管理这块空间有多少个对象,在无对象管理时将其析构),问题二的产生是在我需要修改时才会发生的问题,如果我创建出来不需要修改,只是用来读,这时多开辟的空间显然是有点浪费的。故此引入了写时拷贝,解决问题一可以用引用计数来搞定。

再具体写写时拷贝前,先简单的介绍下引用计数。
引用计数呢是用来统计这块空间现在又多少对象在管理,是一个计数器,所以呢我们可以在构造这个对象时对开辟四个字节用来存储这个ReferenceCount。
这里写图片描述

下面呢简单的实现一下。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
using namespace std;

class String
{
public:
    String(char* str = "")
        :_str(new char[(strlen(str) + 5)])
    {
        *((int*)_str) = 1;
        str += 4;
        strcpy(_str, str);
    }

    String(const String& s)
    {
        _str = s._str;
        ++GetRefCount();
    }

    String& operator=(const String& s)
    {
        if (_str != s._str)
        {
            if (--(GetRefCount()) == 0)
            {
                delete[] _str;
            }

            _str = s._str;
            ++(GetRefCount());

        }

        return *this;
    }

    ~String()
    {
        if (--(GetRefCount()) == 0)
        {
            delete[] (_str - 4);
        }
    }

    int& GetRefCount()
    {
        return *((int*)(_str - 4));
    }
private:
    char* _str;
};

上面就是string类的基本实现,如果需要修改则需要重新开辟空间(多个对象管理),这是查的话则不需要。

备注:
写时拷贝是否不会出错呢?这显然是不可能的,再好的代码也会出错。写时拷贝在单线程时不会出错,但如果是多线程的话还是会出现问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值