• string的模拟实现——C++


    构造函数

    //以上无参式写法变成以下方式会有什么问题?
    string()
    :_str(nullptr)
    , _size(0)
    , _capacity(0)
    {}
    //出现了空指针的错误
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    空指针的错误是由于空对象string s2导致的
    因为空对象初始化给了一个空指针_str(nullptr)
    所以不能这么初始化空对象

    namespace haha
    {
    class string
    {
    public:
    string(const char* str)
    //:_str(str)//不能这样写
    //最好方式是动态开辟空间
    //C++最好使用new,不要使用malloc
    :_str(new char[strlen(str)+1])//多开一个空间
    , _size(strlen(str))
    , _capacity(strlen(str))//capacity不包含\0
    {
    strcpy(_str, str);//拷贝
    }
    
    
    //没有参数的时候,提供全参的或者无缺省的
    //无参
    string()
    
    :_str(new char[1])//方括号要匹配
    , _size(0)
    , _capacity(0)//capacity不包含\0
    {
    _str[0] = '\0';//就算只开一个空间也是给\0的
    //哪怕是个空对象也是给\0
    }
    
    以上无参式写法变成以下方式会有什么问题?
    //string()
    //:_str(nullptr)
    //, _size(0)
    //, _capacity(0)
    //{}
    出现了空指针的错误
    
    
    //全缺省
    //string(const char* str = nullptr)//不能给空指针
    
    //以下两种写法均正确
    //string(const char* str = "\0")//有点画蛇添足的意思
    string(const char* str = "")
                :_str(new char[strlen(str) + 1])//多开一个空间
    , _size(strlen(str))
    , _capacity(strlen(str))
    {
    strcpy(_str, str);
    }
    
    
    
    //析构函数  动态开辟的就要释放掉
    ~string()
    {
    delete[] _str;
    _str = nullptr;
    _size = _capacity = 0;
    }
    
    const char* c_str() const
    {
    return _str;
    }
    
    private:
    char* _str;
    size_t _size;
    size_t _capacity;
    };
    
    void test_string1()
    {
    string s1("hello world");
    string s2;
    
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
    }
    }
    
    • 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
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

     
    优化
    strlen的效率是O(N)

    string(const char* str = "")
    //strlen的效率是O(N)
                :
    _size(strlen(str))
        , _capacity(_size)
                ,_str(new char[_capacity + 1])//多开一个空间
    {
    strcpy(_str, str);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    !这种写法不可以!

    private:
    char* _str;
    size_t _size;
    size_t _capacity;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    初始化是按照声明顺序初始化的!
    所以它不会先初始化_size,而是会先初始化 _str
    初始化 _str的时候_capacity此时还是一个随机值,所以程序会奔溃
    c++的程序里最好去捕获异常

    修改:
    可以换声明顺序(不推荐——》会出现很奇怪的维护问题)
    在私有声明处也可以给缺省值但是没有意义

    推荐方式

    string(const char* str = "")
    {
    _size = strlen(str);
    _capacity = _size;
    _str = new char[_capacity + 1];
    
    strcpy(_str, str);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    namespace bit
    {
    class string
    {
    public:
    string(const char* str)
    //:_str(str)//不能这样写
    //最好方式是动态开辟空间
    //C++最好使用new,不要使用malloc
    :_str(new char[strlen(str)+1])//多开一个空间
    , _size(strlen(str))
    , _capacity(strlen(str))//capacity不包含\0
    {
    strcpy(_str, str);//拷贝
    }
    
    //没有参数的时候,提供全参的或者无缺省的
    //无参
    string()
    
    :_str(new char[1])//方括号要匹配
    , _size(0)
    , _capacity(0)//capacity不包含\0
    {
    _str[0] = '\0';//就算只开一个空间也是给\0的
    //哪怕是个空对象也是给\0
    }
    
    以上无参式写法变成以下方式会有什么问题?
    //string()
    //:_str(nullptr)
    //, _size(0)
    //, _capacity(0)
    //{}
    出现了空指针的错误
    
    
    //全缺省
    //string(const char* str = nullptr)//不能给空指针
    
    //以下两种写法均正确
    //string(const char* str = "\0")//有点画蛇添足的意思
    //string(const char* str = "")
    strlen的效率是O(N)
      //          :_str(new char[strlen(str) + 1])//多开一个空间
    //, _size(strlen(str))
    //, _capacity(strlen(str))
    //{
    //strcpy(_str, str);
    //}
    
    
    //内置类型可以不走初始化列表,初始化列表依赖顺序
    //以下方式使用函数体内
    string(const char* str = "")
    {
    _size = strlen(str);
    _capacity = _size;
    _str = new char[_capacity + 1];
    
    strcpy(_str, str);
    }
    
    
    
    //析构函数  动态开辟的就要释放掉
    ~string()
    {
    delete[] _str;
    _str = nullptr;
    _size = _capacity = 0;
    }
    
    const char* c_str() const
    {
    return _str;
    }
    
    private:
    char* _str;
    size_t _size;
    size_t _capacity;
    };
    
    void test_string1()
    {
    string s1("hello world");
    string s2;
    
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
    }
    }
    
    • 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
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    size

    []遍历

    string(const string& s);
    string& operator = (const string& s);
    
    
    
    const char* c_str() const
    {
    return _str;
    }
    
    size_t size() const
    {
    return _size;
    }
    //普通对象去调用是权限的缩小
    
    //const对象不能修改,只读
    const char& operator[](size_t pos) const
    {
    assert(pos < _size);
    return _str[pos];
    }
    
    //普通对象去调用是可读可写
    char& operator[](size_t pos)
    {
    assert(pos < _size);
    return _str[pos];
    }
    
    
    
    void test_string1()
    {
    string s1("hello world");
    string s2;
    
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
    
    //遍历
    for (size_t i = 0; i < s1.size(); ++i)
    {
    cout << s1[i] << "  ";
    }
    cout << endl;
    
    for (size_t i = 0; i < s1.size(); ++i)
    {
    s1[i]++;
    }
    
    for (size_t i = 0; i < s1.size(); ++i)
    {
    cout << s1[i] << "  ";
    }
    cout << endl;
    
    }
    }
    
    • 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
    • 60

    在这里插入图片描述

    迭代器遍历

    像指针一样的东西,左闭右开
    在这里插入图片描述

    public:
    //迭代器
    typedef char* iterator;
    iterator begin()
    {
    return _str;//返回第一个位置
    }
    
    typedef char* iterator;
    iterator end()
    {
    return _str + _size;//返回最后一个数据的下一个位置
    }
    
     
     
     void test_string2()
    {
    string s1("hello world");
    string::iterator it = s1.begin();
    while (it != s1.end())
    {
    cout << *it << " ";
    ++it;
    }
    cout << endl;
    
    }
    }
    
    • 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

    在这里插入图片描述

    封装的力量
    编译器支持for的时候把它替换成了迭代器
    在这里插入图片描述

    反向迭代器比较复杂——适配器

    const迭代器

    //const 只能读不能写
    typedef const char* const_iterator;
    const_iterator begin() const
    {
    return _str;//返回第一个位置
    }
    
    
    const_iterator end() const
    {
    return _str + _size;//返回最后一个数据的下一个位置
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    拷贝构造

    深浅拷贝问题

    在这里插入图片描述

    浅拷贝:

    两个对象指向同一块空间,会析构两次(同一块空间是不允许释放两次的)
    释放置空的是s2,对s1没有影响
    s1依旧会指向那个空间,但是这个空间已经被释放掉了,所以就会形成野指针的问题

    默认生成拷贝构造,日期类这样的类我们不写可以用,但是对于string的类不能用,需要我们自己去写
     

    最佳方案

    深拷贝:

    指向两块空间,再将数据拷贝过来

    //s2(s1) 拷贝构造
    string(const string& s)//s就是s1的别名
    :_str(new char[s._capacity+1])
    , _size(s._size)
    , _capacity(s._capacity)
    {
    strcpy(_str, s._str);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此时修改,互相之间也不会存在影响,因为是各自独立的空间

    void test_string3()
    {
    string s1("hello world");
    string s2(s1);
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
    
    s2[0] = 'x';
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

     
     

    赋值

    不写用默认的赋值,程序也会奔溃
    发生内存泄漏
    同一个空间会被释放两次(析构会出问题)

    传统写法

    //赋值 s1 = s3
    //this是s1 s是s3
    //string& operator=(const string& s)
    //{
    s1=s1
    //if (this != &s)//取地址
    //{
    //delete[] _str;//用new就用delete 要匹配 []也要匹配
    //_str = new char[s._capacity + 1];//多开一个空间给\0
    //strcpy(_str, s._str);
    //_size = s._size;
    //_capacity = s._capacity;
    //}
    //return *this;
    //}
    
    //优化:先开空间再释放
    string& operator=(const string& s)
    {
    //s1=s1
    if (this != &s)//取地址
    {
    char* tmp = new char[s._capacity + 1];//多开一个空间给\0
    strcpy(tmp, s._str);
    
    delete[] _str;//用new就用delete 要匹配 []也要匹配
    _str = tmp;
    _size = s._size;
    _capacity = s._capacity;
    }
            return *this;
    }
      
      
      
      void test_string3()
    {
    string s1("hello world");
    string s2(s1);
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
    
    s2[0] = 'x';
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
    
    string s3("11111111111111");
    s1 = s3;//将s3赋值给s1
    cout << s1.c_str() << endl;
    cout << s3.c_str() << endl;
    
    s1 = s1;
    cout << s1.c_str() << endl;
    cout << s3.c_str() << endl;
    
    }
    
    • 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

     

    现代写法

    //现代写法
    
    void swap(string& tmp)
    {
    ::swap(_str, tmp._str);
    ::swap(_size, tmp._size);
    ::swap(_capacity, tmp._capacity);
    }
    string(const string& s)
    //初始化一下不要把随机值交换过去
    :_str(nullptr)
    , _size(0)
        , _capacity(0)
    {
    string tmp(s._str);
    /*swap(_str, tmp._str);
    swap(_size, tmp._size);
    swap(_capacity, tmp._capacity);*/
    
    
    swap(tmp);//this->swap(tmp);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

     

    operator赋值的现代写法

    // s1 = s3
    //string& operator=(const string& s)
    //{
    //if (this != &s)
    //{
    string tmp(s._str);
    //
    //      string tmp(s);
    //swap(tmp); // this->swap(tmp);
    //}
    
    //return *this;
    //}
      
      
      // s1 = s3
    // s顶替tmp做打工人
    string& operator=(string s)//s传值传参
    {
    swap(s);
    return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    swap

    在这里插入图片描述

    有两个swap:

    • 库里
    • 全局
    void test_string4()
    {
    string s1("haha");
    string s2("xxxxxxxxxxxx");
    
    //交换成员变量  
    s1.swap(s2);
    //再调拷贝构造
    swap(s1, s2);//代价大,深拷贝不敢用这个
    
    return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

     
     

    增删查改

    void reserve(size_t n)//保留预定 避免扩容
    {
    if (n > _capacity)
    {
    char * tmp = new char[n + 1];
    strcpy(tmp, _str);
    delete[] _str;
    
    _str = tmp;
    _capacity = n;
    }
    }
    
    void push_back(char ch)
    {
    //满了就扩容
    
    //if (_size == _capacity)
    //{
    //reserve(_capacity == 0 ? 4 : _capacity * 2);//避免缺省值是0的情况,0的二倍也是0
    //}
    //_str[_size] = ch;
    //++_size;
    //_str[_size] = '\0';//记得处理\0
    
    insert(_size, ch);
    }
    
    void append(const char* str)
    {
    //size_t len = strlen(str);
    
    //if (_size + len > _capacity)
    //{
    //reserve(_size+len);//至少
    //}
    
    //strcpy(_str + _size, str);
    strcat(_str,str);//需要找\0,效率低  容易被误用
    //_size += len;
    
    insert(_size, str);
    }
    
    
    string& operator+=(char ch)
    {
    push_back(ch);
    return *this;
    }
    
    
    string& operator+=(const char* str)
    {
    append(str);
    return *this;
    }
    
    //void append(const string& s)
    //{
    //append(s._str);
    
    //}
    
    //void append(size_t n, char ch)
    //{
    //reserve(_size + n);
    //for (size_t i = 0; i < n; ++i)
    //{
    //push_back(ch);
    //}
    //}
    
    //在某个位置插入一个字符
    string& insert(size_t pos, char ch)
    {
    assert(pos <= _size);
    
    //满了就扩容
    if (_size == _capacity)
    {
    reserve(_capacity == 0 ? 4 : _capacity * 2);//避免缺省值是0的情况,0的二倍也是0
    }
    
    //挪动数据  pos = 0的时候会越界
    /*size_t end = _size;
    while (end >= pos)
    {
    _str[end + 1] = _str[end];
    --end;
    }*/
    
    size_t end = _size+1;
    while (end >= pos)
    {
    _str[end] = _str[end-1];
    --end;
    }
    
    _str[pos] = ch;
    ++_size;
    
    return *this;
    }
    
    //在某个位置插入字符串
    string& insert(size_t pos, const char* str)
    {
    assert(pos <= _size);
    size_t len = strlen(str);
    if (_size + len > _capacity)
    {
    reserve(_size + len);
    }
    
    // 挪动数据
    size_t end = _size + len;
    while (end >= pos + len)
    {
    //先挪,再动end
    _str[end] = _str[end - len];
    --end;
    }
    
    strncpy(_str + pos, str, len);
    _size += len;
    
    return *this;
    }
    
    
    void erase(size_t pos, size_t len = npos)
    {
    assert(pos < _size);
    
    if (len == npos || pos + len >= _size)
    {
    _str[pos] = '\0';
    _size = pos;
    }
    else
    {
    strcpy(_str + pos, _str + pos + len);
    _size -= len;
    }
    
    }
    
    size_t find(char ch, size_t pos = 0) const;
    size_t find(const char* sub, size_t pos = 0) const;
    bool operator>(const string& s) const;
    bool operator==(const string& s) const;
    bool operator>=(const string& s) const;
    bool operator<=(const string& s) const;
    bool operator<(const string& s) const;
    bool operator!=(const string& s) const;
      
      
      void test_string5()
    {
    string s1("hello");
    cout << s1.c_str() << endl;
    s1 += ' ';
    s1.append("world");
    s1 += "helloooo";
    cout << s1.c_str() << endl;
    
    s1.insert(5, '#');
    cout << s1.c_str() << endl;
    
    }
    
    void test_string6()
    {
    string s1("hello");
    cout << s1.c_str() << endl;
    
    s1.insert(2, "world");
    cout << s1.c_str() << endl;
    
    s1.insert(0, "world");
    cout << s1.c_str() << endl;
    }
    
    void test_string7()
    {
    string s1("hello");
    cout << s1.c_str() << endl;
    
    s1.insert(2, "world");
    cout << s1.c_str() << endl;
    
    s1.insert(0, "world ");
    cout << s1.c_str() << endl;
    }
    
    • 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
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195

     
     

    流提取,流插入

    //流插入
    ostream& operator<<(ostream& out, const string& s)//非必须友元
    {
    for (size_t i = 0; i < s.size(); ++i)
    {
    out << s[i];
    }
    
    return out;
    }
     
      //流提取
    
    //istream& operator>>(istream& in, string& s)
    //{
     输入字符串很长,不断+=,频繁扩容,效率很低,大家可以想法优化一下 
    //char ch;
    in >> ch;
    //ch = in.get();
    //while (ch != ' ' && ch != '\n')
    //{
    //s += ch;
    //ch = in.get();
    //}
    
    //return in;
    //}
    
    istream& operator>>(istream& in, string& s)
    { 
     s.clear();//解决字符串原本就有字符的情况
    char ch;
    
    ch = in.get();
    //s.reserve(128);//一次开够128,缺陷:可能会浪费空间
    
    //局部数组,即用即销毁
    const size_t N = 32;
    char buff[N];
    size_t i = 0;
    
    while (ch != ' ' && ch != '\n')
    {
    buff[i++] = ch;
    if (i == N-1)
    {
    //一批一批的来,扩容也不会一次开很大
    buff[i] = '\0';
    s += buff;
    i = 0;
    }
    ch = in.get();
    }
    
    buff[i] = '\0';
    s += buff;
    
    
    return in;
    }
    
     
     
     void test_string9()
    {
    /*string s1;
    cin >> s1;
    cout << s1 << endl;*/
    
    string s1("hello");
    cout << s1 << endl;//operator<<(cout, s1)
      
    cout << s1.c_str() << endl;
    s1 += '\0';
    s1 += "world";
    cout << s1 << endl;
    cout << s1.c_str() << endl;
    
    
                    string s3, s4;
    cin >> s3 >> s4;
    cout << s3 << s4 << endl;
    }
    
    • 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
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    string类似扩展版的顺序表
    与顺序表不同点:

    • 操纵的是字符串,字符串是以\0结尾的
    • 字符串支持+=
    • 支持比较大小
      ……

    string实现的另一种方案

    深拷贝代价大
    但不能使用浅拷贝进行替换

    浅拷贝问题:

    1. 析构两次
    2. 一个对象修改影响另一个对象

    解决方案

    • 增加一个引用计数。每个对象析构时,–引用计数,最后一个析构的对象释放空间
    • 写时拷贝(本质是延迟可拷贝,谁写谁做深拷贝:没人写就没有深拷贝)
  • 相关阅读:
    VS2022 C# 读取 excel 2023年
    矩阵分解方法(主要是非负矩阵分解)--学习笔记
    Java程序员工作7年,31岁被嫌年龄大,我成为架构师还有多远?
    APP信息侦察&夜神模拟器Burp抓包配置
    maven仓库改国内源
    【git系列2】关于安装 Git 的时候选择 core.autocrlf 的配置值
    使用vue-cli搭建spa项目
    Golang sync.Pool
    标记肽Suc-AAPI-pNA、72682-77-0
    C语言中柔性数组的讲解与柔性数组的优势
  • 原文地址:https://blog.csdn.net/Ll_R_lL/article/details/126907684