【C语言】【面试题】C++中String类引用计数器的浅拷贝写法与深拷贝写法

时间:2023-01-05 19:49:51

Linux操作下String类的实现--引用计数器

    1.引用计数器写法一

写法一个人比较喜欢叫他双指针法,因为他是在类里面创建了两个指针来实现的一个是指针_str,另外一个是用来保存指向同一块空间个数的指针_pRefCount.

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

    String(String& s)
        :_str(s._str)
        , _pRefCount(s._pRefCount)
    {
        ++(*_pRefCount);
    }

    String& operator=(const String& s)
    {
        /*char* tmp = new char[strlen(s._str) + 1];
        strcpy(tmp, s._str);
        delete[] _str;
        _str = tmp;*/ //这种写法不符合引用计数器的原理
        /*swap(_str, s._str);*/
        if (--(*_pRefCount) == 0)
        {
            delete[] _str;
            delete[] _pRefCount;
        }
        _str = s._str;
        _pRefCount = s._pRefCount;
        ++(*_pRefCount);
        return *this;
    }

    ~String()
    {
        if (--(*_pRefCount) == 0)
        {
            delete[] _str;
            delete[] _pRefCount;
        }
    }

private:
    char* _str;
    /*static int _refCount;*///变成静态的以后,需要在类的外面定义
    int* _pRefCount;
};

//int String::_refCount = 0;

void Test1()
{
    String s1("xxx");
    String s2(s1);
    String s3("yyy");
    s3 = s2;
    /*String s4(s3);*/
}

int main()
{
    Test1();
    system("pause");
    return 0;
}

这种写法简单易懂,也容易想到,但是由于要开辟两块空间一块大的一块小的,容易造成系统产生很多的内存碎片,所以有了另外一种写法

    2.引用计数器写法二

这种写法的思路是在开辟空间时多开辟四个字节的空间,在头部用四个字节的空间来保存指向同一块空间的个数,这样即避免了内存碎片的产生,也使得操作起来更为方便,不要要操作两块空间。

class String{public:    String(char* str = "")        :_str(new char[strlen(str) + 5])    {        *(int*)_str = 1;        _str += 4;        strcpy(_str, str);    }    String(String& s)        :_str(s._str)    {        ++(*(int*)(_str - 4));    }    String& operator=(const String& s)    {        if (_str != s._str)        {            Release();            _str = s._str;            ++GetRefCount(_str);        }        return *this;    }    ~String()    {        if (--(*(int*)(_str - 4)) == 0)        {            delete[](_str - 4);        }    }    int& GetRefCount(char* str)    {        return *(int*)(str - 4);    }    void Release()    {        if (--GetRefCount(_str) == 0)        {            delete[](_str - 4);        }    }private:    char* _str;};int main(){    system("pause");    return 0;}