STL初探

STL简介

STL(standard template libaray - 标准模板库)是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。

STL的一些版本

  • 原始版本

Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本即所有STL实现版本的始祖。

  • P. J. 版本

由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,缺陷:可读性比较低,符号命名比较怪异。

  • RW版本

由Rouge Wage公司开发,继承自HP版本,不能公开或修改,可读性一般。

  • SGI版本

由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版本。被GCC采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。

STL的6大组件

STL的一些缺陷

  1. STL库的更新太慢了。上一版靠谱是C++98,中间的C++03基本一些修订。C++11出来已经相隔了13年,STL才进一步更新。
  2.  STL不支持线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的。
  3.  STL极度的追求效率,导致内部比较复杂。比如类型萃取,迭代器萃取。
  4.  STL的使用会有代码膨胀的问题,比如使用vector<int> / vector<double> / vector<char> 这样会生成多份代码,当然这是由于模板语法本身导致的。

                                                                                                        ——截至2023-8-9

string

string的使用

用法参考网址:cplusplus.com/reference/string/string/

string常用API - 用法示例

  • part1:构造与赋值
string s1;			// 无参构造
string s2(10, 65);	// 有参构造,开局10个'A'
string s3("hello world");	// 拷贝构造
s1 = s3;	// operator =
string s4(s3, 2, 5);
const char* str = "abcdefg";
string s5(str);
string s6(str, 5);
  • part2:迭代器

begin():指向容器第一个元素的位置(可读可写)
rbegin():指向容器最后一个元素的位置(可读可写)
cbegin():指向容器第一个元素的位置(只读)
crbegin():指向容器最后一个元素的位置(只读)


end():指向容器最后一个元素的下一个位置(可读可写)
rend():指向容器第一个元素的前一个位置(可读可写)
cend():指向容器最后一个元素的下一个位置(只读)
crend():指向容器第一个元素的前一个位置(只读)

// 正向非常量迭代器,可以正常读写
string str1("hello world");
string::iterator beg = str1.begin();
while (beg != str1.end())
{cout << ++ * beg << " ";beg++;
}
cout << endl;// 反向非常量迭代器,反方向正常读写
string str2("hello world");
string::reverse_iterator rbeg = str2.rbegin();
while (rbeg != str2.rend())
{cout << ++ * rbeg << " ";rbeg++;
}
cout << endl;// 正向常量迭代器,只能读不能写
string str3("hello world");
string::const_iterator cbeg = str3.cbegin();
while (cbeg != str3.end())
{//cout << ++*cbeg << " ";	// errorcout << *cbeg << " ";cbeg++;
}
cout << endl;// 反向常量迭代器,反方向只读不写
string str4("hello world");
string::const_reverse_iterator crbeg = str4.crbegin();
while (crbeg != str4.crend())
{//cout << ++*crbeg << " ";	// errorcout << *crbeg << " ";crbeg++;
}
cout << endl;
  • part3:容量相关
string str = "hello world";
// size方法:Return length of string(不包含最后的'\0')
cout << "str_size: " << str.size() << endl;
// length方法与size方法效果相同
cout << "str_length: " << str.length() << endl;
// max_size方法:Return maximum size of string(没有实际的参考性)
cout << "str_max_size: " << str.max_size() << endl;
// resize方法:改变size,但不改变容量大小
// capacity方法:获取string的容器大小
str.resize(5);
cout << str << endl;
cout << "str_size: " << str.size() << endl;
cout << "str_capacity: " << str.capacity() << endl;
// reverse方法:尝试更改容量大小(只有当变大的时候生效)
str.reserve(5);
cout << "change_5_capacity_result: " << str.capacity() << endl;
str.reserve(20);
cout << "change_20_capacity_result: " << str.capacity() << endl;
// clear方法:清空string
str.clear();
// empty方法:判空
cout << str.empty() << endl;
// shrink_to_fit方法:尝试缩容 
// 函数原型:void shrink_to_fit();
// This function has no effect on the string length and cannot alter its content.
str = "123456789";
cout << "size: " << str.size() << "capacity: " << str.capacity() << endl;
str.shrink_to_fit();
cout << "size: " << str.size() << "capacity: " << str.capacity() << endl;

part4:数据访问

string str = "hello world";
cout << str[3] << endl;  //operator[] - 越界触发断言
cout << str.at(7) << endl;   // at方法 - 越界抛异常
cout << str.back() << endl;   // back方法:访问最后一个字符
cout << str.front() << endl;  // front方法:访问第一个字符

part5:数据操作

string s1 = "hello ";
string s2 = "world";
// operator+=
s1 += s2;
cout << s1 << endl;
// append:在字符串尾添加字符串或单个字符
s2.append(" good");
cout << s2 << endl;
// push_back:尾插单个字符
s1.push_back('!');
cout << s1 << endl;
// assign:赋值,效果与operator=一样
string s3;
s3.assign(s2);
cout << s3 << endl;
// insert:在任意位置插入(下标从0开始)
s3.insert(5, "*******");
cout << s3 << endl;
// erase:按下标/迭代器的位置删除n个
s3.erase(5, 3); // 从下标5开始,删除3个
cout << s3 << endl;
// replace:将指定位置的n个字串替换为另一段字符串
s3.replace(5, 3, " *-* ");
cout << s3 << endl;
// swap:交换两个string对象。对应的size和capacity也原封不动的交换
s3.swap(s2);
cout << s2 << endl;
// pop_back:尾删单个字符
s3.pop_back();
cout << s3 << endl;

string注意事项

  1. 注意resize方法和reverse方法,区分size和capacity:size返回的是字符串长度,而capacity返回的是容器的容量大小。同理。resize调整的是字符串长度,而reverse是尝试调整容量的大小。(reverse并不会改变字符串的内容)
  2. string和其它容器不同。string实际上是basic_string的char型的具体模板类:

    所以这就是为什么string每次使用时不需要显示的指定类型,而其它容器(vector、list等)都需要显示的指定数据类型的原因了。
  3. 其实不光有string一种字符串容器,根据需要我们还可以选择u16string、u32string、wstring等。

模拟实现string

模拟实现string有助于我们更好的理解string的相关功能,更好的体会STL容器的设计。如下是我自己写的部分string功能:

// 输出输出流的重载
ostream& ytc::operator<<(ostream& _cout, const ytc::string& s)
{if (s.empty()) //避免cout一个已释放的stringreturn _cout << "";return _cout << s._str;
}
istream& ytc::operator>>(istream& _cin, ytc::string& s)
{s.clear();char get = _cin.get();while (get != '\n'/* || get != ' '*/) //可以选择读不读空格{if (s._size == s._capacity)s.reserve((s._capacity + 1) * 2);s._str[s._size++] = get;get = _cin.get();}return _cin;
}// 构造和析构
ytc::string::string(const char* str) : _size(strlen(str)), _capacity(strlen(str))
{_str = new char[_capacity + 1];strcpy(_str, str);
}
ytc::string::string(const ytc::string& s)
{_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;
}
ytc::string& ytc::string::operator=(const string& s)
{// 容量检查size_t len = strlen(s._str);reserve(_size + len);// 拷贝内容strcpy(_str, s._str);_size = s._size;return *this;
}
ytc::string::~string()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}// iterator
ytc::string::iterator ytc::string::begin()
{return _str;
}
ytc::string::iterator ytc::string::end()
{return _str + _size;
}// modify
void ytc::string::push_back(char c)
{// 容量检查if (_size == _capacity)reserve((_capacity + 1) * 2);_str[_size++] = c;_str[_size] = '\0';
}
ytc::string& ytc::string::operator+=(char c)
{push_back(c);return *this;
}
void ytc::string::append(const char* str)
{// 容量检查size_t len = strlen(str);reserve(_size + len);// 追加内容strcat(_str, str);_size += len;
}
ytc::string& ytc::string::operator+=(const char* str)
{append(str);return *this;
}
void ytc::string::clear()
{memset(_str, 0, sizeof(char) * _size);_size = 0;
}
void ytc::string::swap(string& s)
{std::swap(_str, s._str);std::swap(_capacity, s._capacity);std::swap(_size, s._size);
}
const char* ytc::string::c_str()const
{return _str;
}// capacity
size_t ytc::string::size()const
{return _size;
}
size_t ytc::string::capacity()const
{return _capacity;
}
bool ytc::string::empty()const
{return _size == 0;
}
void ytc::string::resize(size_t n, char c)
{// n > _size,尾插字符if (n > _size){// 一步到位的扩容reserve(n + 1);// 尾插字符int times = n - _size;while (times--){// 每次添加字符检查一下的扩容/*if (_size == _capacity){_str[_size] = '\0'; //最后加个'\0',防止拷贝的数组比实际的空间大的问题reserve(2 * (_capacity + 1));}*/_str[_size++] = c;}_str[_size] = '\0';}// n < _size,直接截断else if (n < _size){_str[n] = '\0';_size = n;}
}
void ytc::string::reserve(size_t n)
{if (n > _capacity){char* temp = new char[n + 1];strcpy(temp, _str);delete[] _str;_str = temp;_capacity = n;}
}// access
char& ytc::string::operator[](size_t index)
{// 先将*this转换为const对象,然后调用const对象的operator[]// 然后再将其返回的const char转换为charreturn const_cast<char&>(static_cast<const ytc::string&>(*this)[index]);
}
const char& ytc::string::operator[](size_t index)const
{assert(index < _size);return _str[index];
}//relational operators
bool ytc::string::operator<(const string& s)
{return strcmp(_str, s._str) < 0;
}
bool ytc::string::operator<=(const string& s)
{return _str < s._str || _str == s._str;}
bool ytc::string::operator>(const string& s)
{return strcmp(_str, s._str) > 0;
}
bool ytc::string::operator>=(const string& s)
{return _str > s._str || _str == s._str;
}
bool ytc::string::operator==(const string& s)
{return strcmp(_str, s._str) == 0;
}
bool ytc::string::operator!=(const string& s)
{return !(_str == s._str);
}// 返回c在string中第一次出现的位置(下标)
size_t ytc::string::find(char c, size_t pos) const
{if (pos < _size){for (size_t i = pos; i < _size; i++){if (_str[i] == c)return i;}}return npos;
}
// 返回子串s在string中第一次出现的位置
size_t ytc::string::find(const char* s, size_t pos) const
{const char* res = strstr(_str + pos, s);if (res != nullptr){return (res - _str) / sizeof(_str[0]);}return npos;
}
// 在pos位置上插入字符c/字符串str,并返回该字符的位置
ytc::string& ytc::string::insert(size_t pos, char c)
{// 如果pos传的过大了,那么就直接在最后插入if (pos > _size)pos = _size;// 容量检查if (_size == _capacity)reserve((_capacity + 1) * 2);// 字符后移size_t index = _size + 1;while (index >= pos && index + 1 != 0) //后面的条件是控制0位置的特殊情况{_str[index] = _str[index - 1];index--;}_str[pos] = c;_size++;// 最后返回return *this;
}
ytc::string& ytc::string::insert(size_t pos, const char* str)
{// 如果pos传的过大了,那么就直接在最后插入if (pos > _size)pos = _size;// 容量检查size_t len = strlen(str);reserve(_size + len);size_t index = _size;// 字符后移while (index >= pos && index + 1 != 0) //后面的条件是控制0位置的特殊情况{_str[index + len] = _str[index];index--;}strncpy(_str + pos, str, len);_size += len;// 最后返回return *this;
}
// 删除pos位置上的元素,并返回该元素的下一个位置
ytc::string& ytc::string::erase(size_t pos, size_t len)
{if (pos < _size){if (len > _size || pos + len > _size){len = _size - pos + 1;}size_t index = pos;while (index < _size){_str[index] = _str[index + len];index++;}_str[index] = '\0';_size -= len;}else{cout << "删除位置错误!" << endl;}return *this;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1379859.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

PHP最简单自定义自己的框架实现像TP链式sql语句(六)

1、实现效果&#xff0c;链式sql语句封装 order、where、group、limit等封装 2、数据表构造函数入参&#xff0c;ModelBase.php public $table NULL; public function __construct($table){$this->table$table;if(!$this->table){die("no table" );}$this-&…

AI一键生成数字人

AI一键生成数字人,不玩虚的 阅读时长&#xff1a;10分钟 本文内容&#xff1a; 结合开源AI&#xff0c;一键生成短视频发布到常见的某音&#xff0c;某手平台&#xff0c;狠狠赚一笔 前置知识&#xff1a; 基本的 python 编程知识Jupyter Notebook 使用过Linux 使用过 先上源码…

Wallpaper Engine使用视频壁纸黑屏解决方法(window10)

1.点击电脑左下角开始键>设置>搜索框搜索图形设置 2.浏览>找到wallpaper engine相关程序添加 3.将三个的选项改成节能 4.如果软件还在运行&#xff0c;重新启动

WebView2 通过 PuppeteerSharp 实现爬取 王者 壁纸 (案例版)

王者壁纸自动化获取逻辑分析 其实它的逻辑很简单&#xff0c; 就是王者的官网&#xff0c;打开后&#xff0c;在右下角就看到了皮肤页面部分。 这个时候&#xff0c;点击更多&#xff0c;就会打开全部英雄详情的页面。 这个时候&#xff0c;单点任意一个英雄&#xff0c;就会…

微信小程序短视频去水印,王者查战力,手持弹幕,获取头像壁纸,工具箱源码

短视频在线去水印,无任何广告 王者荣耀查荣耀战力已更新 新增加查看历史上的今天 新增手持弹幕&#xff0c;修复剪辑视频不能保存问题。 新增壁纸&#xff0c;头像&#xff0c;网址转二维码。 【微信小程序】&#xff1a;好野工具 【小程序版本】&#xff1a;5.1.1 【小…

王者壁纸批量爬取

语言&#xff1a;python json格式网站&#xff1a; 爬取网址&#xff1a;王者荣耀壁纸下载-王者荣耀官方网站-腾讯游戏 思路分析&#xff1a; 分析下一页&#xff0c;发现下一页之后是在当前页面的局部重新加载 当然排除可以直接爬取目标url获取当前页面的信息以及后面的所…

C语言案例 阶乘求和-12

题目&#xff1a;求1 2&#xff01;3&#xff01; … 20&#xff01;的和。 程序分析 阶乘相关原理&#xff1a;一个正整数的阶乘是所有小于及等于该数的正整数的积&#xff0c;并且0的阶乘为1。自然数n的阶乘写作n!&#xff0c;任何大于1的自然数n阶乘表示方法&#xff1a;…

5大电脑软件推荐!每一款都是精心挑选,良心推荐!

说起实用的电脑软件&#xff0c;我想你看对地方了&#xff0c;世上最棒最实用的电脑软件推荐&#xff01;每一款都十足良心&#xff01; 是时候表演真正的技术了&#xff01; 1.PotPlayer 超受欢迎的播放器之一。这款播放器可能会成为你的菜&#xff0c;内存占用低并且不卡&a…

Windows上有哪些推荐的笔记软件?

说实话&#xff0c;windows上的优秀的笔记软件没有ipad上多&#xff0c;在ipad上的notability、goodnotes、marginnote等优秀的笔记软件&#xff0c;在windows上很少有可替代的产品&#xff0c;不过在windows上也有一些比较优质的笔记软件&#xff0c;对于学生来说&#xff0c;…

3款强大到离谱的电脑软件,个个提效神器,从此远离加班

推荐3款让你偷懒&#xff0c;让你上头的提效电脑软件&#xff0c;个个功能强大&#xff0c;让你远离加班&#xff01; 很多几个小时才能做好的事情&#xff0c;用上它们&#xff0c;只需要5分钟就行&#xff01;&#xff01; 1、Quicker —— 桌面快速启动工具 Quicker鼠标效…

这几款好用的电脑软件推荐给你

软件一&#xff1a;potplayer PotPlayer是一款免费的媒体播放器&#xff0c;它支持多种格式的音频和视频文件。它的界面简洁而且易于使用&#xff0c;让用户可以轻松地播放各种媒体文件。以下是PotPlayer的一些主要功能&#xff1a; 支持多种格式&#xff1a;PotPlayer支持多…

5款超级无敌好用的电脑软件 建议收藏!

1.Quicker Quicker绝对要吹爆&#xff0c;Quicker可以给常用的软件和操作建立捷径&#xff0c;鼠标中键调出快捷面板使用&#xff0c;将常用操作放在手边&#xff0c;绝对的生产力工具&#xff0c;节省大量时间。 支持自定义动作&#xff0c;内置丰富的动作库&#xff0c;可…

电脑推荐软件

个人推荐电脑软件&#xff0c;如需自取。附下载链接&#xff1a; 电脑推荐软件: https://url46.ctfile.com/d/42812846-54181981-4b3214?p7872 (访问密码: 7872) 1、Everything 文件搜索器&#xff0c;快速找出电脑里面所有文件&#xff0c;支持关键字查找。 下载链接&#xf…

3.1 Spring MVC概述

1. MVC概念 MVC是一种编程思想&#xff0c;它将应用分为模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;、控制器&#xff08;Controller&#xff09;三个层次&#xff0c;这三部分以最低的耦合进行协同工作&#xff0c;从而提高应用的可扩展性及可维护…

Vue生命周期函数(详解)

目录 生命周期图 生命周期函数 beforeCreate和created的区别 beforeCreate创建前应用场景 created创建后应用场景 beforeMount和mounted的区别 beforeMount挂载前应用场景 mounted挂载后应用场景 beforeUpdate和updated的区别 beforeUpdate更新前应用场景 updated更新后应用…

数据通信——VRRP

引言 之前把实验做了&#xff0c;结果发现我好像没有写过VRRP的文章&#xff0c;连笔记都没记过。可能是因为对STP的记忆&#xff0c;导致现在都没忘太多。 一&#xff0c;什么是VRRP VRRP全名是虚拟路由冗余协议&#xff0c;虚拟路由&#xff0c;看名字就知道这是运行在三层接…

【前端 | CSS】滚动到底部加载,滚动监听、懒加载

背景 在日常开发过程中&#xff0c;我们会遇到图片懒加载的功能&#xff0c;基本原理是&#xff0c;滚动条滚动到底部后再次获取数据进行渲染。 那怎么判断滚动条是否滚动到底部呢&#xff1f;滚动条滚动到底部触发时间的时机和方法又该怎样定义&#xff1f; 针对以上问题我…

【瑞吉外卖】Linux学习

Linux常用命令 Linux命令初体验 Linux的命令都是由一个或几个单词的缩写构成的 命令对应英文作用lslist查看当前目录下的内容pwdprint work directory查看当前所在目录cd [目录名]change directory切换目录touch [文件名]touch如果文件不存在&#xff0c;新建文件mkdir [目录…

HCIA---动态路由---RIP协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 目录 前言 一.动态路由 二.动态路由协议分类 IGP&#xff1a;内部网关协议 EGP:外部网关协议 三.RIP协议概述 RIP版本分类&#xff1a; RIP三要素&#xff1a; 思维…