C++ —模拟实现 string类

本文详细探讨了C++中字符串类的设计与实现,包括浅拷贝的问题及解决方法,通过四种不同的实现方式展现了深拷贝、引用计数和写时拷贝等技术的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

String类:标准库类型string类表示可变长的字符序列,定义在std中,专门用来管理字符串,下面一起看下它的重要考点。

一:浅拷贝:


class String
{
public:
    String(const char* pStr = "")//构造函数
        :_pStr(new char[strlen(pStr)+1])
    {
        if(0 == *pStr)//字符串为空
        {
            *_pStr = '\0';
        }
        else//字符串不为空
        {
            strcpy(_pStr,pStr);
        }
    }
    String(const String& s)//拷贝构造函数
    {
        _pStr = s._pStr;
    }
    String& operator=(String& s)//赋值运算符重载
    {
        if(_pStr != s._pStr)//判断是不是自己给自己赋值
        {
            _pStr = s._pStr;
        }
        return *this;
    }
    ~String()//析构函数
    {
        if(NULL == _pStr)
        {
            return;
        }
        else
        {
            delete []_pStr;
            _pStr = NULL;
        }
    }
private:
    char* _pStr;
};

二:string四个版本的模拟实现:

1. 深拷贝普通版本

class string
{
public:
    //构造函数
    string(const char* ptr = "")
    {
        if (ptr == NULL)
        {
            _ptr = new char[1];
            *_ptr = '\0';
        }
        _ptr = new char[strlen(ptr) + 1];
        strcpy(_ptr, ptr);
    }
    //拷贝构造函数
    string(const string& s)
        :_ptr(new char[strlen(s._ptr)+1])
    {
        strcpy(_ptr, s._ptr);
    }
    string& operator=(const string& s)
    {
        if (this != &s)
        {
            char* tmp = new char[strlen(s._ptr) + 1];
            strcpy(tmp, s._ptr);
            delete[] _ptr;
            _ptr = tmp;
        }
        return *this;
    }
    ~string()
    {
        if (_ptr)
        {
            delete[] _ptr;
            _ptr = NULL;
        }
    }
private:
    char* _ptr;
};

2. 深拷贝简洁版
版本1:

class string
{
public:
    //构造函数
    string(const char* ptr = "")
    {
        if (ptr == NULL)
        {
            _ptr = new char[1];
            *_ptr = '\0';
        }
        _ptr = new char[strlen(ptr) + 1];
        strcpy(_ptr, ptr);
    }
    //拷贝构造函数
    string(const string& s)
        :_ptr(new char[strlen(s._ptr)+1])
    {
        strcpy(_ptr, s._ptr);
    }
    string& operator=(const string& s)
    {
        if (_ptr!=s.ptr)
        {
            delete[] _ptr;
            _ptr = new char[strlen(s._ptr) + 1];
            strcpy(_ptr, s._ptr);
        }
        return *this;
    }
    ~string()
    {
        if (_ptr)
        {
            delete[] _ptr;
            _ptr = NULL;
        }
    }
private:
    char* _ptr;
};

版本2:

class string
{
public:
    //构造函数
    string(const char* ptr = "")
    {
        if (ptr == NULL)
        {
            _ptr = new char[1];
            *_ptr = '\0';
        }
        _ptr = new char[strlen(ptr) + 1];
        strcpy(_ptr, ptr);
    }
    //拷贝构造函数
    string(const string& s)
        :_ptr(NULL)
    {
        string tmp(s._ptr);
        std::swap(_ptr, tmp._ptr);
    }

    string& operator=(const string& s)
    {
        if (_ptr!=s._ptr)
        {
            string tmp(s._ptr);
            std::swap(_ptr,tmp._ptr);
        }
        return *this;
    }
    ~string()
    {
        if (_ptr)
        {
            delete[] _ptr;
            _ptr = NULL;
        }
    }
private:
    char* _ptr;
};

3. 引用计数

class string
{
public:
    //构造函数
    string(const char* ptr = "")
        :_count(new int[0])
        , _ptr(new char[strlen(ptr)+1])
    {
        if (ptr == NULL)
        {
            _ptr = new char[1];
            *_ptr = '\0';
        }
        else
            strcpy(_ptr, ptr);

        *_count = 1;
    }
    //拷贝构造函数
    string(const string& s)
        :_count(s._count)
    {
        _ptr = (char*)(s._ptr);
        _count = s._count;
        (*_count)++;
    }

    string& operator=(const string& s)
    {
        if (_ptr!=s._ptr)
        {
            _ptr = s._ptr;
            _count = s._count;
            (*_count)++;
        }
        return *this;
    }
    ~string()
    {
        if (_ptr == NULL)
            return;
        else
        {
            if (--(*_count)==0)
            {
                delete[] _ptr;
                delete[] _count;
                _ptr = NULL;
                _count = NULL;
            }
        }
    }
private:
    char* _ptr;
    int* _count;
};

4. 写时拷贝

class string
{
public:
    string(const char* ptr="")
        :_ptr(new char[strlen(ptr)+4+1])//每次多创建4个空间来存放当前地址有几个对象
    {
        if (_ptr == NULL)
        {
            (*(int*)_ptr) = 1;//前四个字节拿来计数
            _ptr += 4;
            *_ptr = '\0';
        }
        else
        {
            (*(int*)_ptr) = 1;
            _ptr += 4;
            strcpy(_ptr, ptr);
        }
    }

    string(const string& s)
        :_ptr(s._ptr)
    {
        ++(*(int*)(_ptr - 4));//向前偏移4个字节将计数加1
    }
    string& operator=(const string& s)
    {
        if (_ptr != s._ptr)
        {
            if (--(*(int*)(_ptr-4)) == 0)
            {
                delete[] _ptr;
                _ptr = NULL;
            }
            _ptr = s._ptr;
            ++(*(int*)(_ptr - 4));
        }
    }

    ~string()
    {
        if (_ptr == NULL)
        {
            return;
        }
        else
        {
            if (--(*(int*)(_ptr - 4)) == 0)
            {
                delete[] (_ptr-4);
                _ptr = NULL;
            }
        }
    }

    char& operator[](size_t index)//下标访问操作符重载
    {
        assert(index >= 0 && index < strlen(_ptr));
        if ((*(int*)(_ptr - 4))>1)//多个对象指向同一块空间
        {
            char* tmp = new char[strlen(_ptr) + 4 + 1];//新开辟一块空间
            tmp += 4;//向后偏移4
            strcpy(tmp,_ptr);
            --(*(int*)(_ptr - 4));//将原来空间的计数器减1

            _ptr = tmp;//将当前对象指向临时空间
            *((int*)(_ptr - 4)) = 1;//将新空间的计数器变为1
        }
        return _ptr[index];
    }
private:
    char* _ptr;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值