【C++】-- STL之String模拟实现(一)

简介: 【C++】-- STL之String模拟实现

一、String类实现

为了和库里面的string 区分开,使用命名空间delia将 string类和库里string隔离开

string类有3个成员变量:_str字符串内容、_size字符串大小、_capacity字符串容量

1. namespace delia
2. {
3.  class string
4.  {
5.     private:
6.         char* _str;
7.      size_t _size;
8.      size_t _capacity;
9.     }
10. }

string的模拟实现包括:

1.string类的构造

分配空间时,要多分配1个字节的空间,这1个字节是留给'\0'的,_size最大为申请字节数-1,_capacity最大也为申请字节数-1

1.         //构造函数
2.    string(const char* str = "")
3.    {
4.      _str = new char[strlen(str) + 1];
5.      strcpy(_str, str);
6. 
7.      _size = strlen(str);
8.      _capacity = _size;
9.    }

 

2.swap()

使用库里的swap函数交换*this和s的内容:包括_str字符串内容、_size字符串大小和_capacity字符串容量

1.         //实现交换函数
2.    void swap(string& s)
3.    {
4.             //用::指定调用全局的swap函数即库里的swap函数
5.      ::swap(_str, s._str);
6.      ::swap(_size, s._size);
7.      ::swap(_capacity, s._capacity);
8.    }

3.拷贝构造

(1)先使用s._str作为参数构造一个临时对象

(2)将临时对象tmp的内容和*this进行交换

注意:必须要在初始化列表进行初始化 ,否则交换完毕后tmp出了拷贝构造函数作用域会调用析构函数释放tmp在堆上申请的空间,因为如果_str没有被初始化为空指针,那么_str就是随机值,交换后,tmp对象的成员_str也是随机值,随机值的空间时不可以被释放的,会导致不可预知的错误;空指针时可以被释放的,因此_str必须被初始化为空指针。

1. //现代拷贝构造
2.    string(const string& s)
3.      :_str(nullptr)
4.      , _size(0)
5.      , _capacity(0)
6.    {
7.      string tmp(s._str);
8.      swap(tmp);
9.    }

4.赋值运算符重载

使用swap()函数将*this的内容和s进行交换

1.         //赋值运算符重载
2.    string& operator=(string s)
3.    {
4.      swap(s);
5.      return *this;
6.    }

 

5.析构

释放_str在对上申请的空间、将_size和_capacity置0

1.      //析构函数
2.    ~string()
3.    {
4.      delete[] _str;
5.      _str = nullptr;
6.      _size = 0;
7.      _capacity = 0;
8.    }

 

6.迭代器

分两种:普通迭代器(可读可写)和const迭代器(只读)

(1)普通迭代器

1.         //迭代器
2.    iterator begin()
3.    {
4.      return _str;
5.    }
6. 
7.    //迭代器
8.    iterator end()
9.    {
10.       return _str + _size;
11.     }

(2)const迭代器

1. //const迭代器
2.    iterator begin() const
3.    {
4.      return _str;
5.    }
6. 
7.    //const迭代器
8.    iterator end() const
9.    {
10.       return _str + _size;
11.     }

 

7.operator[ ]

也分为普通operator[ ](可读可写)和const operator[ ](只读)

char要加&,如果不加,那么return就是传值返回,返回的是_str[i]的拷贝,即临时对象,而临时对象具有常性,不能被修改,只能读;如果要对_str进行修改的话,char要加&,用传引用返回

1.      //const string对象遍历,只读
2.    char& operator[](size_t i)  const
3.    {
4.      assert(i < _size);
5.      return _str[i];
6.    }
7. 
8.    //非const string对象遍历,可读可写
9.    char& operator[](size_t i)
10.     {
11.       assert(i < _size);
12.       return _str[i];
13.     }

 

8.size()

1.      //求string对象大小
2.    size_t size() const
3.    {
4.      return strlen(_str);
5.    }

 

9.c_str()

获取c形式字符串,将 const string* 类型 转化为 const char* 类型

1.      const char* c_str()
2.    {
3.      return _str;
4.    }

 10.reserve()

开空间,扩展_capacity,_size不变

(1)申请新空间

(2)拷贝字符串

(3)释放旧空间

(4)指向新空间

(5)更新容量

1.         void reserve(size_t n)
2.    {
3.      if (n > _capacity)
4.      {
5.        char* tmp = new char[n + 1];//1.申请新空间,多开的那一个空间,存放\0
6.        strncpy(tmp, _str, _size + 1);//2.将字符串包含\0在内都拷贝到新空间
7.        delete[] _str;//3.释放旧空间
8. 
9.        _str = tmp;//4.指向新空间
10.         _capacity = n;//5.更新容量
11.       }
12.     }

11.resize()

开空间+初始化,扩展_capacity,_size也要修改

(1)当n<_size,无需增容

(2)当n>_size,分两种情况

           ①_size < n <_capacity,无需增容,直接将_size到n位置置为val

           ②n >_capacity,需增容,并将_size到n位置置为val

         n>_size的这两种情况只有是否增容的区别,其他没有区别,可以合二为一

1.         void resize(size_t n, char val = '\0')//如果没有显式给出val,val为\0
2.    {
3.      //1.当n<_size,无需增容
4.      if (n < _size)
5.      {
6.        _size = n;//直接更新_size
7.        _str[_size] = '\0';//将_size位置置为\0
8.      }
9.      //2.当n>_size,分两种情况
10.       //(1)_size < n <_capacity,无需增容,直接将_size到n位置置为val
11.       //(2)n >_capacity,需增容,并将_size到n位置置为val
12.       //这两种情况只有是否增容的区别,其他没有区别
13.       else
14.       {
15.         if (n > _capacity)
16.         {
17.           reserve(n);
18.         }
19. 
20.         for (size_t i = _size; i < n; i++)
21.         {
22.           _str[i] = val;
23.         }
24. 
25.         _str[n] = '\0';//将n的位置置\0
26.         _size = n;//更新_size
27.       }
28.     }

 

12.push_back()

要考虑是否需要开空间

1.         //尾插一个字符
2.    void push_back(char ch)
3.    {
4.      //字符个数已经达到容量时,重新开空间
5.      if (_size == _capacity)
6.      {
7.        reserve(_capacity == 0 ? 4 : _capacity * 2);//如果是第一次开空间,就开4个字节,如果不是第一次开空间,就开成原来的2倍容量
8.      }
9. 
10.       _str[_size] = ch;//将字符ch缀到字符串末尾
11.       _str[_size + 1] = '\0';//字符ch后面加\0,表明字符串结束
12.       _size++;//字符串大小+1
13.     }

13.append()

将str内容copy至this._str+_size(*this._str的末尾)位置

 

1.      //追加字符串
2.    void append(const char* str)
3.    {
4.      size_t len = _size + strlen(str);//函数执行完毕后字符串的大小
5. 
6.      if (len > _capacity)
7.      {
8.        reserve(len);//空间不够,增容
9.      }
10. 
11.       strcpy(_str + _size, str);//将str内容拷贝至_str末尾
12.       _size = len;//更新_size
13.     }

 

相关文章
|
1天前
|
C++ 容器
C++ STL:各类容器的特点和优缺点比较
C++ STL:各类容器的特点、优势、劣势比较
|
3天前
|
存储 算法 C++
C++一分钟之-标准模板库(STL)简介
【6月更文挑战第21天】C++ STL是高效通用的算法和数据结构集,简化编程任务。核心包括容器(如vector、list)、迭代器、算法(如sort、find)和适配器。常见问题涉及内存泄漏、迭代器失效、效率和算法误用。通过示例展示了如何排序、遍历和查找元素。掌握STL能提升效率,学习过程需注意常见陷阱。
20 4
|
7天前
|
算法 前端开发 Linux
【常用技巧】C++ STL容器操作:6种常用场景算法
STL在Linux C++中使用的非常普遍,掌握并合适的使用各种容器至关重要!
33 10
|
1天前
|
存储 安全 算法
C++的内置数组和STL array、STL vector
C++的内置数组和STL array、STL vector
|
5天前
|
存储 编译器 C++
|
5天前
|
C语言 C++
C++对C的改进和拓展\string类型
C++对C的改进和拓展\string类型
8 1
|
9天前
|
存储 算法 程序员
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
18 4
|
9天前
|
存储 算法 程序员
【C++进阶】深入STL之vector:构建高效C++程序的基石
【C++进阶】深入STL之vector:构建高效C++程序的基石
16 1
|
9天前
|
存储 缓存 编译器
【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
10 0
|
9天前
|
C++ 容器
【C++进阶】深入STL之list:高效双向链表的使用技巧
【C++进阶】深入STL之list:高效双向链表的使用技巧
14 0