【无标题】浅谈c++ string底层实现机制

本文探讨了C++中string类的底层实现策略,包括深拷贝(EagerCopy)、写时复制(CopyOnWrite)机制以及引用计数,旨在提高字符串操作的效率。同时,提到了对于短字符串的优化(SSO),即当字符串长度小于16字节时在栈上存储,否则在堆上分配空间。通过示例代码展示了如何在自定义string类中实现这些功能。
摘要由CSDN通过智能技术生成

###== 浅谈c++ string底层实现方式==

c++底层实现采用了三种策略:

深拷贝Eager Copy

特点:当复制构造或者复制时,两个对象的指针不会指向同一块内存空间,会申请新的空间,并将数据惊醒复制。

缺点:在频繁复制而并不改变字符串内容时,效率低下,为了解决这总问题,采用写时复制的机制

写时复制 [COW] (Copy On Write)

特点:当两个string发生复制构造或者复制时,不会复制字符串的内容,两个对象的指针指向的是同一块内存空间,只有当一个字符串发生修改操作,才会执执行真正的复制。

实现策略:浅拷贝+引用计数

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <cstring>

using std::cout;
using std::endl;

class String
{
public:

    //refCount + value;
    String()
    :_pstr(new char[4 + 1]() + 4)//_pstr始终指向数据部分,新增四个字节时引用计数
    {
        cout << "String()" << endl;
        *(int *)(_pstr - 4) = 1;
    }
    
    String(const char* pstr)
    {
        cout << "String(const char* pstr)" << endl;
        if(pstr == nullptr)
        {
            _pstr = new char[5]() + 4;   //指向数据部分
            *(int *)(_pstr - 4) = 1;
            return;
        }
        
        _pstr = new char[strlen(pstr) + 5]() + 4;
        strcpy(_pstr,pstr);
        *(int *)(_pstr - 4) = 1;
    }

    String(const String& rhs)
    {
        cout << "String(const String& rhs)" << endl;

        //判断rhs._pstr是否是nullptr
        if(rhs._pstr == nullptr)
        {
            _pstr = new char[5]() + 4;   //指向数据部分
            *(int *)(_pstr - 4) = 1;
            return;
        }
        _pstr = rhs._pstr;  //浅拷贝+refCount
        ++*(int *)(_pstr - 4);
    }

    //s2 = s1;
    String& operator=(const String& rhs)
    {
        cout << "String& operator=(const String& rhs)" << endl;
        //避免自复制
        if(this == &rhs)
        {
            return *this;
        }

        //释放左操作数,引用计数-1,判断引用计数是否为0,为零则delete
        --*(int *)(_pstr -4);
        if(*(int *)(_pstr - 4) == 0)
        {
            delete[] (_pstr-4);
        }

        //浅拷贝
        _pstr = rhs._pstr;     //?
        ++*(int *)(_pstr - 4);
        
        return *this;
    }
    
    char& operator[](size_t index)
    {
        if(index < 0 || index >= size())
        {
            std::cerr << "operator[index] 'index outOfRange or invalid_argument" << endl;
            static char nullchar = '\0';
            return nullchar;
        }
        //表明是共享的,执行写时复制
        if(getRefCount() > 1)
        {
            char* ptmp = new char[size() + 5]() + 4;
            strcpy(ptmp,_pstr);
            --*(int *)(_pstr - 4);
            _pstr = ptmp;
            *(int *)(_pstr - 4) = 1;
        }
        return _pstr[index];
    }



    ~String()
    {
        cout << "~String()" << endl;
        
        --*(int *)(_pstr - 4);
        if(*(int *)(_pstr - 4) == 0)
        {
            delete[] (_pstr - 4);   //-4,不然会泄露四个字节
        }
    }

    const char* c_str() const
    {
        return _pstr;
    }

    int getRefCount() const 
    {
        return *(int *)(_pstr - 4);
    }
    size_t size() const
    {
        return strlen(_pstr);
    }

    friend std::ostream& operator <<(std::ostream& os, const String& rhs);
private:
    char* _pstr;
};



std::ostream& operator <<(std::ostream& os, const String& rhs)
{
    if(rhs._pstr) 
    {
        os << rhs._pstr;
    }
    return os;
}



void test()
{

    String s1("hello");
    cout << "s1 = " << s1 << endl;
    printf("s1's address:%p\n",s1.c_str());
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;

    cout << endl;
    String s2 = s1;
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    printf("s1's address:%p\n",s1.c_str());
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    printf("s2's address:%p\n",s2.c_str());
    cout << "s2.getRefCount() = " << s2.getRefCount() << endl;

    cout << endl;
    String s3("world");
    cout << "s3 = " << s3 << endl;
    printf("s3's address:%p\n",s3.c_str());
    cout << "s3.getRefCount() = " << s3.getRefCount() << endl;

    cout << endl;
    s3 = s1;
    printf("s1's address:%p\n",s1.c_str());
    printf("s2's address:%p\n",s2.c_str());
    printf("s3's address:%p\n",s3.c_str());
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() << endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() << endl;

    cout << endl << "对s3[0]执行写操作" << endl;
    s3[0] = 'H';
    s3[1] = 'Y';
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    printf("s1's address:%p\n",s1.c_str());
    printf("s2's address:%p\n",s2.c_str());
    printf("s3's address:%p\n",s3.c_str());
    cout << "s1.getRefCount() = " << s1.getRefCount() << endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() << endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() << endl;
    
}

int main()
{
    test();
    return 0;
}

运行结果
在这里插入图片描述

短字符串优化[SSO] (Short string Optinization)

特点:当字符串小于16Byte时,在栈上申请空间存储字符串,当字符串长度>=16Byte,在堆上申请空间用于存储字符串。

在这里插入图片描述

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;
//短字符串优化
void test()
{
    int *pInt = new int(10);
    string s1 = "hello";//当str长度小于16字节时,字符串存储再栈上
    string s2 = "wuhanwangdaohub";//当字符串长度大于等于16字节时,字符串存储在堆上
    string s3 = "welcometowuhanwangdao";

    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    printf("s1'saddress : %p\n", s1.c_str());
    printf("s2'saddress : %p\n", s2.c_str());
    printf("s3'saddress : %p\n", s3.c_str());
    printf("pInt's address : %p\n", &pInt);
    printf("pInt's  Pointer address : %p\n", pInt);


    delete pInt;
}

int main(int argc, char **argv)
{
    test();
    return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值