【C++】C++STL 揭秘:Strng背后的底层逻辑(二)

简介: 【C++】C++STL 揭秘:Strng背后的底层逻辑

【C++】C++STL 揭秘:Strng背后的底层逻辑(一)https://developer.aliyun.com/article/1617335


十三、push_back

void push_back(char ch)
{
    // 扩容2倍
    if (_size == _capacity)
    {
        reserve(_capacity == 0 ? 4 : 2 * _capacity);
    }
    _str[_size] = ch;
    ++_size;
    _str[_size] = '\0';
    //insert(_size, ch);
}

说明:

  1. 插入单个字符时,需要判断空间是否充足
  2. 跟顺序表的尾插差不多
  3. 实现任意位置插入,直接内部调用insert也是可以的

十四、append

void append(const char* str)
    {
        // 扩容
        size_t len = strlen(str);
        if (_size + len > _capacity)
        {
            reserve(_size + len);
        }
        strcpy(_str + _size, str);//在尾部拷贝完成添加操作
        _size += len;
        
        //insert(_size, str);
    }

说明:

  1. 当然可以选择一开始直接扩容
  2. 插入字符串时,需要判断空间是否充足
  3. 跟顺序表的尾插差不多
  4. 实现任意位置插入,直接内部调用insert也是可以的

十五、operator +=

string& operator+=(char ch)
    {
        push_back(ch);
        return *this;
    }
    string& operator+=(const char* str)
    {
        append(str);
        return *this;
    }

十六、find

16.1 寻找字符

size_t find(char ch, size_t pos = 0) const
{
    assert(pos < _size);
    for (size_t i = pos; i < _size; i++)
    {
        if (_str[i] == ch)
            return i;
    }
    return npos;
}

说明:

  1. 从任意位置遍历,找到返回该位置索引
  2. 没有找到就返回npos(-1)
  3. const修饰函数,仅限于读权限

16.2 寻找字符串

size_t find(const char* sub, size_t pos = 0) const
{
    assert(pos < _size);
    const char* p = strstr(_str + pos, sub);
    if (p)
    {
        return p - _str;
    }
    else
    {
        return npos;
    }
}

说明:

  1. strstr匹配所需字符串,返回匹配到字符串第一个位置
  2. 如果为空,表示不存在
  3. 如果找到了,利用指针-指针,得到下标位置索引

十七、substr

string substr(size_t pos = 0, size_t len = npos)
{
    string sub;
    //if (len == npos || len >= _size-pos)
    if (len >= _size - pos)
    {
        for (size_t i = pos; i < _size; i++)
        {
            sub += _str[i];
        }
    }
    else
    {
        for (size_t i = pos; i < pos + len; i++)
        {
            sub += _str[i];
        }
    }
    return sub;
}

说明:

  1. substr功能是返回从指定位置开始len长度的字符串
  2. 先创建string空对象用于接收截取字符串
  3. len == nposlen >= _size - pos,代表了从pos位置到尾的字符串截取。
  4. 尽量书写len >= _size - pos,而不是len + pos >= _size这种,是为了防止len + pos超过类型最大值范围

十八、clear

void clear()
    {
        _size = 0;
        _str[_size] = '\0';
    }

清空资源,不释放空间

十九、erase

void erase(size_t pos = 0, size_t len = npos)
{
    assert(pos <= _size);
    if (pos > _size - len || len==npos)
    {
        _str[pos] = '\0';
        _size = pos;
    }
    else
    {
        strcpy(_str + pos, _str + pos + len);
        _size -= len;
    }
}

具体说明:如果长度大于从指定位置到结束位置的长度,只需要在pos位置设置结束标识符。不然的话,就是将需要清空位置被后面的内容覆盖就行。如果对于strcpy这块逻辑不明白,可以回顾下strcpy使用方法。

二十、运算符重载

bool operator==(const string& s1, const string& s2)
  {
    int ret = strcmp(s1.c_str(), s2.c_str());
    return ret == 0;
  }
  bool operator<(const string& s1, const string& s2)
  {
    int ret = strcmp(s1.c_str(), s2.c_str());
    return ret < 0;
  }
  bool operator<=(const string& s1, const string& s2)
  {
    return s1 < s2 || s1 == s2;
  }
  bool operator>(const string& s1, const string& s2)
  {
    return !(s1 <= s2);
  }
  bool operator>=(const string& s1, const string& s2)
  {
    return !(s1 < s2);
  }
  bool operator!=(const string& s1, const string& s2)
  {
    return !(s1 == s2);
  }

说明:跟类和对象实现日期Date是一样的,具体有需要点击该连接日期类

二十一、实现迭代器

21.1 可读可修改

typedef char* iterator;
    iterator begin()
    {
        return _str;
    }
    iterator end()
    {
        return _str + _size;
    }

22.2 可读不可修改

typedef const char* iterator;
    const_iterator begin() const
    {
        return _str;
    }
    const_iterator end() const
    {
        return _str + _size;
    }

说明:

  1. 迭代器是一个像指针的东西,可以是指针,也可以不是指针,具体还需要看底层实现
  2. 这里使用指针实现迭代器,返回第一个位置和最后一个位置的下一个位置。

二十三、模拟实现流插入和流提取

23.1 operator<<(流插入)

#include<iostream>
using namespace std;
ostream& operator<<(ostream& out, const string& s)
    {
        for (auto ch : s)
        {
            out << ch;
        }
        return out;
    }

说明:

  • operator是C++标准库中的一个类,用于输出数据流,位于标准命名空间std中。对此需要引用std命名空间访问。
  • out << ch;重载的<<运算符用于将字符ch写入输出流out是C++标准库中重载

23.2 operator>>(流提取)

istream& operator>>(istream& in, string& s)
{
    s.clear();
    char ch;
    //in >> ch;
    ch = in.get();
    char buff[128];
    size_t i = 0;
    while (ch != ' ' && ch != '\n')
    {
        buff[i++] = ch;
        // [0,126]
        if (i == 127)
        {
            buff[127] = '\0';
            s += buff;
            i = 0;
        }
        ch = in.get();
    }
    if (i > 0)
    {
        buff[i] = '\0';
        s += buff;
    }
    return in;
}

具体流程:首先clear先清空对象中的资源,这里需要考虑char类型的最大值为128,创建个数组用于输入到类中,使用operator+=将得到的字符串输入到对象中。

流提取是将从键盘中读取的数据存储到s对象中,至于返回类型为istream&是为支持连续流提取操作cin >> s >> s2。string中getline接口模拟实现是一样的就不展开.


【C++】C++STL 揭秘:Strng背后的底层逻辑(三)https://developer.aliyun.com/article/1617337

目录
打赏
0
1
1
0
21
分享
相关文章
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
106 2
【c++丨STL】map/multimap的使用
本文详细介绍了STL关联式容器中的`map`和`multimap`的使用方法。`map`基于红黑树实现,内部元素按键自动升序排列,存储键值对,支持通过键访问或修改值;而`multimap`允许存在重复键。文章从构造函数、迭代器、容量接口、元素访问接口、增删操作到其他操作接口全面解析了`map`的功能,并通过实例演示了如何用`map`统计字符串数组中各元素的出现次数。最后对比了`map`与`set`的区别,强调了`map`在处理键值关系时的优势。
217 73
【c++丨STL】set/multiset的使用
本文深入解析了STL中的`set`和`multiset`容器,二者均为关联式容器,底层基于红黑树实现。`set`支持唯一性元素存储并自动排序,适用于高效查找场景;`multiset`允许重复元素。两者均具备O(logN)的插入、删除与查找复杂度。文章详细介绍了构造函数、迭代器、容量接口、增删操作(如`insert`、`erase`)、查找统计(如`find`、`count`)及`multiset`特有的区间操作(如`lower_bound`、`upper_bound`、`equal_range`)。最后预告了`map`容器的学习,其作为键值对存储的关联式容器,同样基于红黑树,具有高效操作特性。
149 3
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
205 1
|
6月前
|
【c++丨STL】stack和queue的使用及模拟实现
本文介绍了STL中的两个重要容器适配器:栈(stack)和队列(queue)。容器适配器是在已有容器基础上添加新特性或功能的结构,如栈基于顺序表或链表限制操作实现。文章详细讲解了stack和queue的主要成员函数(empty、size、top/front/back、push/pop、swap),并提供了使用示例和模拟实现代码。通过这些内容,读者可以更好地理解这两种数据结构的工作原理及其实现方法。最后,作者鼓励读者点赞支持。 总结:本文深入浅出地讲解了STL中stack和queue的使用方法及其模拟实现,帮助读者掌握这两种容器适配器的特性和应用场景。
131 21
深入浅出 C++ STL:解锁高效编程的秘密武器
C++ 标准模板库(STL)是现代 C++ 的核心部分之一,为开发者提供了丰富的预定义数据结构和算法,极大地提升了编程效率和代码的可读性。理解和掌握 STL 对于 C++ 开发者来说至关重要。以下是对 STL 的详细介绍,涵盖其基础知识、发展历史、核心组件、重要性和学习方法。
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
42 0
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
107 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问