商城网站设计价格,怎么做网站镜像,教育培训机构平台,网站存在风险什么意思引言#xff1a;STL简介
什么是STL STL(standard template libaray-标准模板库)#xff1a; 是 C标准库的重要组成部分#xff08;注意#xff1a;STL只是C标准库里的一部分#xff0c;cin和cout也是属于C标准库的#xff09;#xff0c;不仅是一个可复用的组件库…引言STL简介
什么是STL
STL(standard template libaray-标准模板库) 是 C标准库的重要组成部分注意STL只是C标准库里的一部分cin和cout也是属于C标准库的不仅是一个可复用的组件库而且 是一个包罗数据结构与算法的软件框架。 STL的六大组件 string类
概念
string是管理字符数组的顺序表。
标准库中的string类
sting类的文档介绍连接cplusplus.com/reference/string/string/?kwstring string类的常用接口说明
1.常见构造 注意
#includeiostream
using namespace std;int main()
{string s1;string s2(张三);// string (const char* s);string s3(hello world);string s4(10, *);// string (size_t n, char c);string s5(s2);// string (const string str);cout s1 endl;cout s2 endl;cout s4 endl;cout s5 endl;// 使用s3的子串初始化s6从索引6开始长度为5的子串即worldstring s6(s3, 6, 5);// string (const string str, size_t pos, size_t len npos);cout s3 endl;cout s6 endl;// 使用s3的子串初始化s7从索引6开始到s3的末尾即worldstring s7(s3, 6);cout s7 endl;string s8(s3, 6, 100);// 尝试从s3的索引6开始获取长度为100的子串但s3的长度不足所以只取到s3的末尾即worldcout s8 endl;string url(https://en.cppreference.com/w/);string sub1(url, 0, 5);string sub2(url, 8, 15);string sub3(url, 22);cout sub1 endl;cout sub2 endl;cout sub3 endl;return 0;
}
2.赋值操作 #includeiostream
using namespace std;int main()
{string s1;string s2(张三);s1 s2;cout s1 endl;return 0;
}
3.容量操作 注意 size()与length()方法底层实现原理完全相同引入size()的原因是为了与其他容器的接口保持一致一般情况下基本都是用size()。 clear()只是将string中有效字符清空不改变底层空间大小。 reserve(size_t res_arg0)在C的string使用中调用reserve(100)函数理论上应确保字符串对象至少预留足够的空间来存储100个字符不包括终止的空字符\0。然而实际预留的空间大小可能因编译器和库实现的不同而有所差异。在GCC等Linux环境下的编译器中string的实现可能会严格遵守reserve的请求调用后capacity()返回的值接近或等于100。而在VS特别是VS2013及更早版本中由于可能采用了“短字符串优化”技术调用reserve(100)后capacity()返回的值可能会远大于100以减少未来内存分配的次数。此外不同编译器和库实现中的string类对于内存管理的策略如释放多余空间和扩大容量等也可能有所不同。值得注意的是为string预留空间时如果reserve的参数小于字符串当前的底层空间总大小那么reserve不会改变其容量大小。resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个不同的是当字符个数增多时resize(n)用0来填充多出的元素空间resize(size_t n, char c)用字符c来填充多出的元素空间。注意resize在改变元素个数时如果是将元素个数增多可能会改变底层容量的大小如果是将元素个数减少底层空间总大小不变。
#includeiostream
using namespace std;void test_size_lenth_capacity()
{string s1 Hello World!;cout s1.size() endl;cout s1.length() endl;cout s1.capacity() endl;if (!s1.empty()) {s1.clear();cout s1.empty() endl;cout s1.size() endl;//清除后的有效字符个数会变cout s1.length() endl;cout s1.capacity() endl;//但是清除后的容量不会变}
}void testReserve()
{string s;s.reserve(100);size_t sz s.capacity();cout capacity changed: sz \n;cout making s grow:\n;for (int i 0; i 100; i){s.push_back(c);if (sz ! s.capacity()){sz s.capacity();cout capacity changed: sz \n;}}s.clear();cout capacity changed: sz \n;s.reserve(10);sz s.capacity();cout capacity changed: sz \n;
}void testResize()
{string s1 Hello World!;s1.reserve(50);cout Reserved capacity of string: s1.capacity() endl;// resize: 改变字符串的大小如果新大小大于当前大小则填充字符默认是空字符s1.resize(20, *);cout Resized string: s1 endl;
}void test_shrink_to_fit()
{string s1 Hello World!;cout Current capacity of string: s1.capacity() endl;s1.reserve(50);cout Reserved capacity of string: s1.capacity() endl;s1.shrink_to_fit();cout shrink the capacity of s1 to fit: s1.capacity() endl;
}
4.访问及遍历操作 注意operator[]有两种形式用于访问字符串中的字符
非const版本用于非常量字符串允许读取和修改字符。例如str[i] A; 可以改变字符串str中索引为i的字符。const版本用于常量字符串或当您不希望修改字符串时它只允许读取字符而不允许修改。尝试修改const字符串中的字符会导致编译错误。
重点补充迭代器
定义
迭代器iterator是一种类似指针的对象用于访问容器中的元素。它可能是一个指针也可能是一个封装了指针行为的对象。迭代器提供了对容器元素的顺序访问可以遍历容器中的元素。
迭代器的使用
1.普通迭代器和反向迭代器的使用
普通迭代器允许读写容器中的元素反向迭代器允许我们从后向前遍历容器。以下是一个使用迭代器遍历并修改 string 对象的例子
#include iostream
#include string
using namespace std;int main() {string s1(hello world);//普通迭代器string::iterator it s1.begin();while (it ! s1.end()) {(*it)--; // 将每个字符的ASCII值减1it;}cout s1 endl; // 输出修改后的字符串//反向迭代器auto rit s1.rbegin();// 使用auto关键字简化类型声明while (rit ! s1.rend()){(*rit) ;// 将每个字符的ASCII值加1rit;}cout s1 endl;return 0;
}
2.const迭代器的使用
对于 const 对象或需要保证不修改容器内容的场景应使用 const 迭代器。const 迭代器只能读取元素不能修改。
#include iostream
#include string
using namespace std;void Func(const std::string s) {string::const_iterator it s.begin();while (it ! s.end()) {cout *it ;it;}cout endl;auto rit s.rbegin(); // 使用auto关键字简化类型声明while (rit ! s.rend()) {cout *rit ;rit;}cout endl;
}int main() {string s1(hello world);Func(s1);return 0;
}
迭代器的意义 修改元素迭代器可以像指针一样解引用并修改元素在非 const 迭代器的情况下。 范围for循环C11引入了范围for循环底层通过迭代器实现简化了遍历容器的代码。 #include iostream
#include string
using namespace std;int main() {string s1(hello world);for (auto ch : s1) {ch; // 将每个字符的ASCII值加1}cout s1 endl;for (char ch : s1) {cout ch ;}cout endl;return 0;
} 通用性几乎所有标准容器如 vector、list、map 等都支持迭代器并且用法类似。这使得代码更加通用和可移植。 #include iostream
#include vector
#include list
using namespace std;int main() {vectorint v {1, 2, 3, 4};vectorint::iterator vit v.begin();while (vit ! v.end()) {cout *vit ;vit;}cout endl;listint lt {10, 20, 3, 4};listint::iterator lit lt.begin();while (lit ! lt.end()) {cout *lit ;lit;}cout endl;return 0;
} 限制对于非连续存储的容器如 list、map不能使用下标操作符 [] 访问元素因为它们的空间结构不是连续的。 与算法配合STL算法如 reverse、sort 等通过迭代器操作容器中的元素使得算法与容器解耦提高了代码的灵活性和复用性。 #include iostream
#include vector
#include list
#include algorithm
using namespace std;int main() {vectorint v {1, 2, 3, 4};listint lt {10, 20, 3, 4};reverse(v.begin(), v.end());reverse(lt.begin(), lt.end());for (auto e : v) {cout e ;}cout endl;for (auto e : lt) {cout e ;}cout endl;sort(v.begin(), v.end());for (auto e : v) {cout e ;}cout endl;return 0;
}
补充at的代码示例
void testAt()
{string s1 Hello World!;cout s1.at(2) endl;s1.at(2) O;cout s1 endl;
}5.修改操作
函数名称功能说明push_back在字符串末尾添加一个字符append在字符串末尾追加一个字符串operator使用加法运算符追加字符串或字符assign覆盖赋值用新字符串替换原字符串内容insert在指定位置插入字符串或字符不建议频繁使用会影响效率erase删除指定位置或范围内的字符不建议频繁使用会影响效率pop_back删除字符串末尾的字符replace替换指定范围内的字符为新的字符串或字符
void test01()
{string s1(hello world);s1.append(ssssss); // s1 变为 hello worldsssssss1.push_back(a); // s1 变为 hello worldssssssas1 abc; // s1 变为 hello worldssssssa abcs1.assign(111111111); // s1 变为 111111111s1.insert(0, hello); // s1 变为 hello111111111s1.insert(5, world); // s1 变为 helloworld11111s1.insert(0, 10, x); // s1 变为 xxxxxxxxxxhelloworld111s1.insert(s1.begin()10, 10, y); // s1 变为 xxxxxxxxxxhyyyyyyyworld11
}void test02()
{string s1(hello world);s1.erase(5, 1); // 删除从位置5开始的1个字符s1 变为 hello world - helloworlds1.erase(5); // 删除从位置5开始的剩余所有字符默认行为s1 变为 hellostring s2(hello world);s2.erase(0, 1); // 删除从位置0开始的1个字符s2 变为 hello world - ello worlds2.erase(s2.begin()); // 删除迭代器指向的第一个字符s2 变为 llo world
}void test03()
{//world替换成 xxxxxxxxxxxxxxxxxxxxxxstring s1(hello world hello lynn);s1.replace(6, 5, xxxxxxxxxxxxxxxxxxxxxx); // 替换 world 为 xxxxxxxxxxxxxxxxxxxxxxcout s1 endl; // 再次替换s1 变为 hello yyyyys1.replace(6, 23, yyyyy);cout s1 endl;// 所有空格替换成20%string s2(hello world hello bit);string s3;for (auto ch : s2){if (ch ! ){s3 ch;}else{s3 20%;}}s2 s3; // s2 变为 hello20%world20%hello20%lynn
}
6.字符串操作
函数名称功能说明c_str返回一个指向以空字符结尾的字符数组的指针该字符数组是字符串的副本常用于与C语言接口函数的交互。find用于查找子字符串或字符在字符串中第一次出现的位置。rfind用于查找子字符串或字符在字符串中最后一次出现的位置。find_first_of用于查找字符串中第一次出现参数中任一字符的位置。find_last_of用于查找字符串中最后一次出现参数中任一字符的位置。substr用于查找字符串中最后一次出现参数中任一字符的位置。
void test_c_str() {string str Hello, World!;const char* cStr str.c_str();cout cStr endl; // 输出: Hello, World!
}void test_find() {string str Hello, World!;size_t pos str.find(World);if (pos ! string::npos) {cout Found World at position: pos endl; // 输出: Found World at position: 7}else {cout World not found endl;}
}void test_rfind() {string str Hello, Hello World!;size_t pos str.rfind(Hello);if (pos ! string::npos) {cout Found Hello last time at position: pos endl; // 输出: Found Hello last time at position: 13}else {cout Hello not found endl;}
}void test_find_first_of() {string str Hello, World!;size_t pos str.find_first_of(aeiou);if (pos ! string::npos) {cout Found first vowel at position: pos endl; // 输出: Found first vowel at position: 1 (e in Hello)}else {cout No vowel found endl;}
}void test_find_last_of() {string str Hello, World!;size_t pos str.find_last_of(aeiou);if (pos ! string::npos) {cout Found last vowel at position: pos endl; // 输出: Found last vowel at position: 8 (o in World)}else {cout No vowel found endl;}
}void test_substr() {string str Hello, World!;string subStr1 str.substr(7, 5); // 从位置7开始长度为5的子字符串cout Substring1: subStr1 endl; // 输出: Substring1: Worldstring subStr2 str.substr(2, 6); // 从位置2开始长度为6的子字符串cout Substring2: subStr2 endl; // 输出: Substring2: llo, W
}
7.string类非成员函数
函数名称功能说明operator重载输出流运算符用于将自定义类型的数据输出到输出流。operator重载输入流运算符用于从输入流中读取数据到自定义类型。getlinegetline 是标准库函数用于从输入流中读取一行文本直到遇到换行符\n换行符会被丢弃不会存储在字符串中。operator重载operator用于连接两个字符串。 operator、operator、 operator、 operator、 operator、 operator! 重载关系运算符如, , , , , !用于比较自定义类型的对象。 当使用关系运算符比较两个字符串时比较是逐字符进行的基于Unicode码点值。
#includealgorithm
using namespace std;int main() {string s1, s2;cin s1;//如果输入空格就会停止输入cout s1 endl;//注意如果 cin s1; 读取后留下了换行符getline() 会立即读取到这个换行符并停// 止读取认为已经读取了一行实际上是一个空行。因此s2 会是一个空字符串。// 为了避免这种问题我们要通过cin.ignore(); 忽略缓冲区中的换行符。cin.ignore();// 忽略缓冲区中的下一个字符通常是换行符getline(cin, s2);//如果输入空格不会停止输入直到遇到换行符\n才会停止输入cout s2 endl;string s3 s1 s2;cout s3 endl;string s4, s5;s4 abcd;s5 abc;if (s4 s5) {cout s4 s5 endl;}else {cout s4 s5 endl;}return 0;
}
8.字符串转换函数
函数名称功能说明 stoi 将字符串转换为整数int stof 将字符串转换为单精度浮点数float stod 将字符串转换为双精度浮点数double stoll 将字符串转换为长长整数long long to_string 将数值转换为字符串
int main() {string str1 123;int num1 stoi(str1);cout The int value is: num1 endl;string str2 123.456;float num2 stof(str2);cout The float value is: num2 endl;string str3 123;double num3 stod(str3);cout The double value is: num3 endl;string str4 12345678910111213;long long num4 stoll(str4);cout The long long value is: num4 endl;int num5 123;string str5 to_string(num5);cout The string value is: str5 endl;long long num6 1234567;string str6 to_string(num6);cout The string value is: str6 endl;double num7 3.14;string str7 to_string(num7);cout The string value is: str7 endl;return 0;
}
写时拷贝了解
一、浅拷贝问题
析构两次浅拷贝只复制了对象的指针导致两个对象共享同一块内存。当这两个对象被分别析构时会尝试对同一块内存进行两次释放从而引发错误。一个对象修改会影响另一个由于浅拷贝只是复制了指针所以两个对象实际上指向的是同一块数据。因此当一个对象的数据被修改时另一个对象的数据也会相应地被改变。
二、深拷贝问题
内存开销深拷贝需要复制对象的所有数据包括嵌套对象这可能导致较大的内存开销。写时拷贝优化为解决深拷贝的内存开销问题可采用写时拷贝策略。 初始时对象间共享数据内存引用计数跟踪使用对象数量。 当某个对象尝试修改数据时若引用计数大于1则进行深拷贝生成新的数据副本以避免影响其他对象。引用计数管理 注意引用计数需正确管理以确保内存安全释放。 当对象被复制时引用计数增加当对象被销毁或不再被引用时引用计数减少。 引用计数降为0时释放对象及其数据内存。