第27章 字符串和流

C++20新特性:字符串相关增强

C++20对字符串处理进行了多项增强,包括format库、char8_t支持等:

std::format库

C++20引入了std::format库,提供了一种类型安全、灵活的字符串格式化方法:

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
#include <format>
#include <string>
#include <iostream>

int main() {
// 基本格式化
std::string message = std::format("Hello, {}!", "world");
std::cout << message << std::endl; // 输出:Hello, world!

// 多个参数
std::string info = std::format("Name: {}, Age: {}", "Alice", 30);
std::cout << info << std::endl; // 输出:Name: Alice, Age: 30

// 格式化数字
std::string number = std::format("Pi is approximately {:.2f}", 3.14159);
std::cout << number << std::endl; // 输出:Pi is approximately 3.14

// 格式化宽度和对齐
std::string aligned = std::format("{:<10} {:>10}", "Left", "Right");
std::cout << aligned << std::endl; // 输出:Left Right

// 格式化进制
std::string hex = std::format("Decimal: {}, Hex: {:x}, Octal: {:o}", 42, 42, 42);
std::cout << hex << std::endl; // 输出:Decimal: 42, Hex: 2a, Octal: 52

// 格式化日期和时间
auto now = std::chrono::system_clock::now();
std::string time_str = std::format("Current time: {:%Y-%m-%d %H:%M:%S}", now);
std::cout << time_str << std::endl;

return 0;
}

char8_t类型

C++20引入了char8_t类型,专门用于UTF-8编码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <string>

int main() {
// UTF-8字符串字面量
const char8_t* utf8_str = u8"Hello, 世界!";

// std::u8string
std::u8string u8s = u8"Hello, 世界!";
std::cout << "Length of u8string: " << u8s.size() << std::endl;

// 注意:需要适当的转换才能输出到cout
// 这里只是演示char8_t的使用

return 0;
}

string类

string类的基本操作

string类是C++标准库中用于处理字符串的类,它提供了丰富的字符串操作功能。

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
#include <string>
#include <iostream>

int main() {
// 字符串初始化
std::string s1; // 空字符串
std::string s2("Hello"); // 用C风格字符串初始化
std::string s3(s2); // 复制构造函数
std::string s4(5, 'a'); // 5个'a'字符
std::string s5(s2, 1, 3); // 从s2的第1个位置开始,取3个字符

// 字符串赋值
s1 = "World";
s1 = s2;
s1.assign("Hello World");
s1.assign("Hello World", 5); // 只取前5个字符
s1.assign(3, 'x'); // 3个'x'字符

// 字符串连接
s1 = "Hello";
s2 = "World";
std::string s6 = s1 + " " + s2;
s1 += " " + s2;
s1.append("!");
s1.append(" C++", 4); // 只取前4个字符

// 字符串长度
std::cout << "Length of s1: " << s1.length() << std::endl;
std::cout << "Size of s1: " << s1.size() << std::endl;
std::cout << "Empty: " << (s1.empty() ? "Yes" : "No") << std::endl;

// 字符串访问
std::cout << "First character: " << s1[0] << std::endl;
std::cout << "Second character: " << s1.at(1) << std::endl;

// 字符串修改
s1[0] = 'h';
s1.at(1) = 'e';

// 字符串查找
size_t pos = s1.find("World");
if (pos != std::string::npos) {
std::cout << "Found 'World' at position: " << pos << std::endl;
}

pos = s1.rfind("o");
if (pos != std::string::npos) {
std::cout << "Last 'o' at position: " << pos << std::endl;
}

// 字符串替换
s1.replace(6, 5, "C++"); // 从位置6开始,替换5个字符为"C++"

// 字符串插入
s1.insert(6, " ");

// 字符串删除
s1.erase(6, 1); // 从位置6开始,删除1个字符

// 字符串比较
if (s1 == s2) {
std::cout << "s1 == s2" << std::endl;
} else if (s1 > s2) {
std::cout << "s1 > s2" << std::endl;
} else {
std::cout << "s1 < s2" << std::endl;
}

// 字符串子串
std::string substr = s1.substr(0, 5); // 从位置0开始,取5个字符
std::cout << "Substring: " << substr << std::endl;

// C风格字符串转换
const char* cstr = s1.c_str();
std::cout << "C-style string: " << cstr << std::endl;

// 数值转换
std::string numStr = "12345";
int num = std::stoi(numStr);
std::cout << "String to int: " << num << std::endl;

double dbl = std::stod("3.14");
std::cout << "String to double: " << dbl << std::endl;

// 数值转字符串
std::string intStr = std::to_string(12345);
std::cout << "Int to string: " << intStr << std::endl;

return 0;
}

string类的迭代器

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
#include <string>
#include <iostream>

int main() {
std::string s = "Hello, World!";

// 正向迭代器
std::cout << "Forward iteration: " << std::endl;
for (auto it = s.begin(); it != s.end(); ++it) {
std::cout << *it;
}
std::cout << std::endl;

// 反向迭代器
std::cout << "Reverse iteration: " << std::endl;
for (auto it = s.rbegin(); it != s.rend(); ++it) {
std::cout << *it;
}
std::cout << std::endl;

// 常量正向迭代器
std::cout << "Constant forward iteration: " << std::endl;
for (auto it = s.cbegin(); it != s.cend(); ++it) {
std::cout << *it;
}
std::cout << std::endl;

// 常量反向迭代器
std::cout << "Constant reverse iteration: " << std::endl;
for (auto it = s.crbegin(); it != s.crend(); ++it) {
std::cout << *it;
}
std::cout << std::endl;

// 范围for循环
std::cout << "Range-based for loop: " << std::endl;
for (char c : s) {
std::cout << c;
}
std::cout << std::endl;

return 0;
}

string类的算法

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
#include <string>
#include <iostream>
#include <algorithm>

int main() {
std::string s = "Hello, World!";

// 转换为大写
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
std::cout << "Uppercase: " << s << std::endl;

// 转换为小写
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
std::cout << "Lowercase: " << s << std::endl;

// 反转字符串
std::reverse(s.begin(), s.end());
std::cout << "Reversed: " << s << std::endl;

// 排序字符串
std::sort(s.begin(), s.end());
std::cout << "Sorted: " << s << std::endl;

// 去重
auto last = std::unique(s.begin(), s.end());
s.erase(last, s.end());
std::cout << "Unique: " << s << std::endl;

return 0;
}

标准模板库(STL)

STL的组成部分

STL由以下几个部分组成:

  1. 容器(Containers):用于存储数据的对象
  2. 迭代器(Iterators):用于遍历容器中的元素
  3. 算法(Algorithms):用于操作容器中的元素
  4. 函数对象(Functors):行为类似函数的对象
  5. 适配器(Adapters):修改其他STL组件接口的组件
  6. 分配器(Allocators):用于管理内存分配

容器

序列容器

序列容器按顺序存储元素,包括:

  • vector:动态数组,随机访问快
  • list:双向链表,插入删除快
  • deque:双端队列,两端插入删除快
  • array:固定大小数组(C++11+)
  • forward_list:单向链表(C++11+)
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
#include <vector>
#include <list>
#include <deque>
#include <array>
#include <forward_list>
#include <iostream>

int main() {
// vector
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.push_back(6);
vec.pop_back();
std::cout << "Vector: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// list
std::list<int> lst = {1, 2, 3, 4, 5};
lst.push_back(6);
lst.push_front(0);
lst.pop_back();
lst.pop_front();
std::cout << "List: " << std::endl;
for (int num : lst) {
std::cout << num << " ";
}
std::cout << std::endl;

// deque
std::deque<int> dq = {1, 2, 3, 4, 5};
dq.push_back(6);
dq.push_front(0);
dq.pop_back();
dq.pop_front();
std::cout << "Deque: " << std::endl;
for (int num : dq) {
std::cout << num << " ";
}
std::cout << std::endl;

// array
std::array<int, 5> arr = {1, 2, 3, 4, 5};
std::cout << "Array: " << std::endl;
for (int num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;

// forward_list
std::forward_list<int> flst = {1, 2, 3, 4, 5};
flst.push_front(0);
flst.pop_front();
std::cout << "Forward list: " << std::endl;
for (int num : flst) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

关联容器

关联容器按键存储元素,包括:

  • set:有序集合,键唯一
  • multiset:有序集合,键可重复
  • map:有序映射,键值对,键唯一
  • multimap:有序映射,键值对,键可重复
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
#include <set>
#include <map>
#include <iostream>

int main() {
// set
std::set<int> s = {3, 1, 4, 1, 5, 9, 2, 6};
s.insert(7);
s.erase(1);
std::cout << "Set: " << std::endl;
for (int num : s) {
std::cout << num << " ";
}
std::cout << std::endl;

// 查找元素
auto it = s.find(5);
if (it != s.end()) {
std::cout << "Found 5" << std::endl;
}

// multiset
std::multiset<int> ms = {3, 1, 4, 1, 5, 9, 2, 6};
ms.insert(1);
std::cout << "Multiset: " << std::endl;
for (int num : ms) {
std::cout << num << " ";
}
std::cout << std::endl;

// map
std::map<std::string, int> m;
m["one"] = 1;
m["two"] = 2;
m["three"] = 3;
m.insert({"four", 4});
std::cout << "Map: " << std::endl;
for (const auto& pair : m) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

// 查找元素
auto it2 = m.find("two");
if (it2 != m.end()) {
std::cout << "Found two: " << it2->second << std::endl;
}

// multimap
std::multimap<std::string, int> mm;
mm.insert({"one", 1});
mm.insert({"one", 11});
mm.insert({"two", 2});
std::cout << "Multimap: " << std::endl;
for (const auto& pair : mm) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

return 0;
}

无序容器(C++11+)

无序容器使用哈希表实现,包括:

  • unordered_set:无序集合,键唯一
  • unordered_multiset:无序集合,键可重复
  • unordered_map:无序映射,键值对,键唯一
  • unordered_multimap:无序映射,键值对,键可重复
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
#include <unordered_set>
#include <unordered_map>
#include <iostream>

int main() {
// unordered_set
std::unordered_set<int> us = {3, 1, 4, 1, 5, 9, 2, 6};
us.insert(7);
us.erase(1);
std::cout << "Unordered set: " << std::endl;
for (int num : us) {
std::cout << num << " ";
}
std::cout << std::endl;

// unordered_map
std::unordered_map<std::string, int> um;
um["one"] = 1;
um["two"] = 2;
um["three"] = 3;
um.insert({"four", 4});
std::cout << "Unordered map: " << std::endl;
for (const auto& pair : um) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

return 0;
}

迭代器

迭代器是一种抽象的设计概念,它提供了一种方法来访问容器中的元素,而不暴露容器的底层表示。

迭代器类型

迭代器类型功能支持的操作
输入迭代器只读,单向移动++, *, ->, ==, !=
输出迭代器只写,单向移动++, *
前向迭代器读写,单向移动++, *, ->, ==, !=
双向迭代器读写,双向移动++, –, *, ->, ==, !=
随机访问迭代器读写,随机访问++, –, *, ->, ==, !=, +, -, +=, -=, []

迭代器使用示例

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
#include <vector>
#include <list>
#include <iostream>

int main() {
// vector 支持随机访问迭代器
std::vector<int> vec = {1, 2, 3, 4, 5};
std::cout << "Vector: " << std::endl;
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;

// 随机访问
std::cout << "Third element: " << *(vec.begin() + 2) << std::endl;
std::cout << "Using []: " << vec[2] << std::endl;

// list 支持双向迭代器
std::list<int> lst = {1, 2, 3, 4, 5};
std::cout << "List: " << std::endl;
for (auto it = lst.begin(); it != lst.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;

// 双向移动
auto it = lst.end();
--it;
std::cout << "Last element: " << *it << std::endl;

return 0;
}

算法

STL提供了大量的算法,用于操作容器中的元素。这些算法定义在<algorithm>头文件中。

常用算法

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
#include <vector>
#include <algorithm>
#include <iostream>

int main() {
std::vector<int> vec = {5, 2, 8, 1, 9, 3, 7, 4, 6};

// 排序
std::sort(vec.begin(), vec.end());
std::cout << "Sorted: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// 反转
std::reverse(vec.begin(), vec.end());
std::cout << "Reversed: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// 查找
auto it = std::find(vec.begin(), vec.end(), 5);
if (it != vec.end()) {
std::cout << "Found 5 at position: " << std::distance(vec.begin(), it) << std::endl;
}

// 计数
int count = std::count(vec.begin(), vec.end(), 5);
std::cout << "Count of 5: " << count << std::endl;

// 最大值
auto maxIt = std::max_element(vec.begin(), vec.end());
std::cout << "Max element: " << *maxIt << std::endl;

// 最小值
auto minIt = std::min_element(vec.begin(), vec.end());
std::cout << "Min element: " << *minIt << std::endl;

// 求和
int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::cout << "Sum: " << sum << std::endl;

// 填充
std::fill(vec.begin(), vec.begin() + 3, 0);
std::cout << "After fill: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// 替换
std::replace(vec.begin(), vec.end(), 0, 10);
std::cout << "After replace: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// 复制
std::vector<int> vec2(vec.size());
std::copy(vec.begin(), vec.end(), vec2.begin());
std::cout << "Copied vector: " << std::endl;
for (int num : vec2) {
std::cout << num << " ";
}
std::cout << std::endl;

// 交换
std::swap(vec[0], vec[1]);
std::cout << "After swap: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

谓词和函数对象

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
#include <vector>
#include <algorithm>
#include <iostream>

// 函数对象
class GreaterThan {
private:
int value;

public:
GreaterThan(int v) : value(v) {}

bool operator()(int num) const {
return num > value;
}
};

int main() {
std::vector<int> vec = {5, 2, 8, 1, 9, 3, 7, 4, 6};

// 使用函数对象
int threshold = 5;
GreaterThan gt(threshold);

// 计数大于threshold的元素
int count = std::count_if(vec.begin(), vec.end(), gt);
std::cout << "Count of elements greater than " << threshold << ": " << count << std::endl;

// 使用lambda表达式
count = std::count_if(vec.begin(), vec.end(), [threshold](int num) { return num > threshold; });
std::cout << "Count using lambda: " << count << std::endl;

// 排序(降序)
std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; });
std::cout << "Sorted in descending order: " << std::endl;
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

// 查找第一个大于threshold的元素
auto it = std::find_if(vec.begin(), vec.end(), [threshold](int num) { return num > threshold; });
if (it != vec.end()) {
std::cout << "First element greater than " << threshold << ": " << *it << std::endl;
}

return 0;
}

函数对象

函数对象是重载了函数调用运算符()的类的实例,也称为仿函数。

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
#include <vector>
#include <algorithm>
#include <iostream>

// 函数对象
class Add {
private:
int value;

public:
Add(int v) : value(v) {}

int operator()(int x) const {
return x + value;
}
};

class Multiply {
private:
int factor;

public:
Multiply(int f) : factor(f) {}

int operator()(int x) const {
return x * factor;
}
};

int main() {
// 使用函数对象
Add add5(5);
int result1 = add5(10);
std::cout << "10 + 5 = " << result1 << std::endl;

Multiply multiply3(3);
int result2 = multiply3(10);
std::cout << "10 * 3 = " << result2 << std::endl;

// 函数对象作为参数
std::vector<int> vec = {1, 2, 3, 4, 5};
std::vector<int> result(vec.size());

std::transform(vec.begin(), vec.end(), result.begin(), add5);
std::cout << "After adding 5: " << std::endl;
for (int num : result) {
std::cout << num << " ";
}
std::cout << std::endl;

std::transform(vec.begin(), vec.end(), result.begin(), multiply3);
std::cout << "After multiplying by 3: " << std::endl;
for (int num : result) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

适配器

STL提供了三种适配器:容器适配器、迭代器适配器和函数适配器。

容器适配器

容器适配器修改容器的接口,提供不同的使用方式:

  • stack:栈,后进先出(LIFO)
  • queue:队列,先进先出(FIFO)
  • priority_queue:优先队列,最高优先级元素先出
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
#include <stack>
#include <queue>
#include <iostream>

int main() {
// stack
std::stack<int> s;
s.push(10);
s.push(20);
s.push(30);

std::cout << "Stack size: " << s.size() << std::endl;
std::cout << "Top element: " << s.top() << std::endl;

s.pop();
std::cout << "After pop, top element: " << s.top() << std::endl;

// queue
std::queue<int> q;
q.push(10);
q.push(20);
q.push(30);

std::cout << "Queue size: " << q.size() << std::endl;
std::cout << "Front element: " << q.front() << std::endl;
std::cout << "Back element: " << q.back() << std::endl;

q.pop();
std::cout << "After pop, front element: " << q.front() << std::endl;

// priority_queue
std::priority_queue<int> pq;
pq.push(30);
pq.push(10);
pq.push(50);
pq.push(20);

std::cout << "Priority queue size: " << pq.size() << std::endl;
std::cout << "Top element: " << pq.top() << std::endl; // 最大的元素

pq.pop();
std::cout << "After pop, top element: " << pq.top() << std::endl;

return 0;
}

最佳实践

1. string类的使用

  • 优先使用string:相比C风格字符串,string更安全、更方便
  • 避免不必要的拷贝:使用引用传递字符串
  • 合理使用reserve:对于大型字符串操作,使用reserve预分配空间
  • 注意字符串比较:使用==运算符或compare方法,而不是strcmp
  • 使用STL算法:对string使用STL算法时,注意string的特性

2. STL容器的选择

场景推荐容器原因
随机访问频繁vector随机访问时间复杂度O(1)
插入删除频繁list插入删除时间复杂度O(1)
两端插入删除deque两端操作时间复杂度O(1)
固定大小数组array编译期大小,更高效
查找频繁set/map查找时间复杂度O(log n)
无序查找unordered_set/unordered_map平均查找时间复杂度O(1)
栈操作stack后进先出
队列操作queue先进先出
优先队列priority_queue最高优先级元素先出

3. 迭代器的使用

  • 使用auto:使用auto推导迭代器类型,提高代码可读性
  • 注意迭代器失效:在修改容器时,注意迭代器可能失效
  • 优先使用范围for:对于简单遍历,使用范围for循环
  • 使用const迭代器:对于只读操作,使用const迭代器

4. 算法的使用

  • 了解算法的时间复杂度:选择合适的算法
  • 使用合适的谓词:根据需要使用函数对象或lambda表达式
  • 注意算法的要求:不同算法对迭代器类型有不同要求
  • 优先使用STL算法:避免手写循环,提高代码可读性和效率

5. 函数对象和Lambda

  • 对于复杂逻辑:使用函数对象,提高代码可读性
  • 对于简单逻辑:使用Lambda表达式,简化代码
  • 注意捕获列表:避免不必要的捕获,防止变量生命周期问题
  • 使用mutable:需要修改捕获变量时,使用mutable关键字

常见错误和陷阱

1. string类的错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 错误:越界访问
std::string s = "Hello";
char c = s[10]; // 未定义行为

// 正确:使用at()进行边界检查
try {
char c = s.at(10);
} catch (const std::out_of_range& e) {
std::cout << "Out of range: " << e.what() << std::endl;
}

// 错误:使用过时的函数
std::string s = "Hello";
s.copy(buffer, 10); // 不推荐使用

// 正确:使用c_str()或data()
const char* cstr = s.c_str();

2. 容器使用错误

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
// 错误:在遍历过程中修改vector
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); ++it) {
if (*it == 3) {
vec.erase(it); // 错误:迭代器失效
}
}

// 正确:使用erase的返回值
for (auto it = vec.begin(); it != vec.end();) {
if (*it == 3) {
it = vec.erase(it);
} else {
++it;
}
}

// 错误:使用错误的容器
// 需要频繁查找时使用vector
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = std::find(vec.begin(), vec.end(), 5); // 时间复杂度O(n)

// 正确:使用set
std::set<int> s = {1, 2, 3, 4, 5};
auto it = s.find(5); // 时间复杂度O(log n)

3. 迭代器错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 错误:使用已失效的迭代器
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin();
vec.push_back(6); // 可能导致迭代器失效
std::cout << *it << std::endl; // 未定义行为

// 正确:重新获取迭代器
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin();
vec.push_back(6);
it = vec.begin(); // 重新获取
std::cout << *it << std::endl;

// 错误:使用错误的迭代器类型
std::list<int> lst = {1, 2, 3, 4, 5};
auto it = lst.begin();
std::cout << *(it + 2) << std::endl; // 错误:list的迭代器不支持随机访问

// 正确:使用循环移动迭代器
std::list<int> lst = {1, 2, 3, 4, 5};
auto it = lst.begin();
std::advance(it, 2); // 移动2个位置
std::cout << *it << std::endl;

4. 算法使用错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 错误:使用不匹配的算法
std::list<int> lst = {5, 2, 8, 1, 9};
std::sort(lst.begin(), lst.end()); // 错误:list的迭代器不支持随机访问

// 正确:使用list的成员函数
lst.sort();

// 错误:未提供足够的空间
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst;
std::copy(src.begin(), src.end(), dst.begin()); // 错误:dst为空

// 正确:使用back_inserter
std::copy(src.begin(), src.end(), std::back_inserter(dst));
// 或预分配空间
dst.resize(src.size());
std::copy(src.begin(), src.end(), dst.begin());

小结

本章介绍了C++中的string类和标准模板库(STL),包括:

  1. string类:基本操作、迭代器、算法
  2. STL的组成部分:容器、迭代器、算法、函数对象、适配器、分配器
  3. STL容器:序列容器、关联容器、无序容器
  4. STL迭代器:类型、使用方法
  5. STL算法:常用算法、谓词和函数对象
  6. STL函数对象:使用方法
  7. STL适配器:容器适配器
  8. 最佳实践:string类的使用、容器选择、迭代器使用、算法使用、函数对象和Lambda
  9. 常见错误和陷阱:string类错误、容器使用错误、迭代器错误、算法使用错误

string类和STL是C++标准库的重要组成部分,它们提供了丰富的工具和组件,大大提高了编程效率和代码质量。掌握这些内容对于成为一名优秀的C++程序员至关重要。在实际编程中,应根据具体情况选择合适的工具和方法,遵循最佳实践,避免常见错误。

在后续章节中,我们将学习C++的输入输出、文件操作、模板特化等内容,进一步提高C++编程能力。