当前位置:   article > 正文

string类深拷贝,写时拷贝_string赋值是深拷贝吗 java

string赋值是深拷贝吗 java

在实现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;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

上面呢就是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;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/501726
推荐阅读
相关标签
  

闽ICP备14008679号