大纲
近容器
概念介绍
在 C++ 中,常见的近容器有以下几种:
迭代器
概念介绍
在 C++ 中,常见的迭代器有以下几种:
iterator
和 const_iterator
reverse_iterator
和 const_reverse_iterator
提示
在 C++ 中,iterator
迭代器是从 const_iterator
迭代器继承而来的。
案例代码
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
| #include <iostream> #include <vector> #include <time.h>
using namespace std;
int main() { srand(time(nullptr));
vector<int> v1;
for (int i=0; i< 10; i++) { v1.push_back(rand() % 100 + 1); }
for (vector<int>::iterator it = v1.begin(); it!= v1.end(); ++it){ if (*it % 2 ==0 ){ *it = *it + 1; } cout << *it << " "; } cout << endl;
for (vector<int>::const_iterator it = v1.begin(); it!= v1.end(); ++it){ if (*it % 2 ==0 ){ } cout << *it << " "; } cout << endl;
for (vector<int>::reverse_iterator it = v1.rbegin(); it!= v1.rend(); ++it){ if (*it % 2 ==0 ){ *it = *it + 1; } cout << *it << " "; } cout << endl;
for (vector<int>::const_reverse_iterator it = v1.rbegin(); it!= v1.rend(); ++it){ if (*it % 2 ==0 ){ } cout << *it << " "; } cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2 3 4
| 25 93 69 85 75 19 79 39 13 19 25 93 69 85 75 19 79 39 13 19 19 13 39 79 19 75 85 69 93 25 19 13 39 79 19 75 85 69 93 25
|
函数对象
概念介绍
- C++ 中的函数对象,其作用类似 C 语言中的函数指针。
- 在 C++ 中,将拥有
operator()
小括号运算符重载函数的对象称作 “函数对象”,或者称作 “仿函数”。 - 通过函数对象调用
operator ()
,会产生内联的效果,其执行效率比较高,因为没有函数调用的开销。 - 由于函数对象是使用类生成的,因此函数对象可以拥有相关的成员变量,比如可以通过成员变量来记录函数对象的使用次数。
- 在 C++ 中,常见的函数对象有:
less
、greater
。
案例代码一
这里主要演示 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
| #include <iostream>
using namespace std;
template<typename T> bool my_greater(T a, T b) { return a > b; }
template<typename T> bool my_less(T a, T b) { return a < b; }
template<typename T, typename Compare> bool compare(T a, T b, Compare func) { return func(a, b); }
int main() { cout << compare(1, 3, my_greater<int>) << endl; cout << compare(1, 3, my_less<int>) << endl; return 0; }
|
程序运行输出的结果如下:
案例代码二
这里主要演示 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
| #include <iostream>
using namespace std;
template<typename T>
class mygreater {
public: bool operator()(T a, T b) { return a > b; }
};
template<typename T>
class myless {
public: bool operator()(T a, T b) { return a < b; }
};
template<typename T, typename Compare> bool compare(T a, T b, Compare func) { return func(a, b); }
int main() { cout << compare(1, 3, mygreater<int>()) << endl; cout << compare(1, 3, myless<int>()) << endl; return 0; }
|
程序运行输出的结果如下:
案例代码三
这里主要演示如何在 C++ 的 STL 中使用函数对象。
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
| #include <iostream> #include <vector> #include <queue> #include <set>
using namespace std;
void test01() { cout << "============ test01() ============" << endl;
priority_queue<int, vector<int>, greater<int>> q1; for (int i = 0; i < 10; i++) { int val = rand() % 100 + 1; q1.push(val); cout << val << " "; } cout << endl;
while (!q1.empty()) { cout << q1.top() << " "; q1.pop(); } cout << endl; }
void test02() { cout << "============ test02() ============" << endl;
set<int, greater<int>> s1; for (int i = 0; i < 10; i++) { int val = rand() % 100 + 1; s1.insert(val); cout << val << " "; } cout << endl;
for (set<int>::iterator it = s1.begin(); it != s1.end(); ++it) { cout << *it << " "; } cout << endl;
}
int main() { srand(time(nullptr));
test01(); test02(); return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5 6
| ============ test01() ============ 4 64 45 55 2 82 62 84 51 74 2 4 45 51 55 62 64 74 82 84 ============ test02() ============ 40 8 50 65 100 26 48 34 43 43 100 65 50 48 43 40 34 26 8
|
泛型算法
概念介绍
- C++ 泛型算法 = 模板(Template) + 迭代器 + 函数对象。
- C++ 泛型算法的参数接收的都是迭代器,而且还可以接收函数对象。
- C++ 常见的泛型算法有以下几种:
sort
:排序算法find
:查找算法find_if
:条件查找算法binary_search
:二分查找算法for_each
:遍历算法
特别注意
二分查找算法(binary_search
)并不适用于降序排序(从大到小)的容器,只适用于升序排序(从小到大)的容器,因为它默认是按照升序排序来查找元素的。
案例代码一
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 <iostream> #include <vector> #include <algorithm>
using namespace std;
int main() { int arr[] = {12, 23, 7, 11, 39, 25, 45, 48, 58}; vector<int> v1(arr, arr + sizeof(arr) / sizeof(arr[0]));
for (int val : v1) { cout << val << " "; } cout << endl;
sort(v1.begin(), v1.end());
for (int val : v1) { cout << val << " "; } cout << endl;
vector<int>::iterator it1 = find(v1.begin(), v1.end(), 48); if (it1 != v1.end()) { cout << "found number 48" << endl; } else { cout << "not found 48" << endl; }
if (binary_search(v1.begin(), v1.end(), 25)) { cout << "found number 25" << endl; } else { cout << "not found 25" << endl; }
return 0; }
|
程序运行输出的结果如下:
1 2 3 4
| 12 23 7 11 39 25 45 48 58 7 11 12 23 25 39 45 48 58 found number 48 found number 25
|
案例代码二
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
| #include <iostream> #include <vector> #include <algorithm> #include <functional>
using namespace std;
int main() { int arr[] = {22, 33, 8, 21, 59, 35, 55, 63, 70}; vector<int> v1(arr, arr + sizeof(arr) / sizeof(arr[0]));
sort(v1.begin(), v1.end());
for (int val : v1) { cout << val << " "; } cout << endl;
vector<int>::iterator it2 = find_if(v1.begin(), v1.end(), bind1st(less<int>(), 48));
v1.insert(it2, 48);
for (int val : v1) { cout << val << " "; } cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2
| 8 21 22 33 35 55 59 63 70 8 21 22 33 35 48 55 59 63 70
|
案例代码三
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
| #include <iostream> #include <vector> #include <algorithm>
using namespace std;
int main() { srand(time(nullptr));
vector<int> v1; for (int i = 0; i < 10; i++) { v1.push_back(rand() % 100 + 1); }
for (int val : v1) { cout << val << " "; } cout << endl;
for_each(v1.begin(), v1.end(), [](int val) -> void { if (val % 2 == 0) { cout << val << " "; } }); cout << endl;
return 0; }
|
程序运行输出的结果如下:
1 2
| 46 81 98 43 35 60 61 68 77 96 46 98 60 68 96
|
容器原理
emplace () 函数剖析
核心概念
在 C++ 标准模板库(STL)中,大多数容器提供了类似 emplace_xxx()
的函数,比如 emplace_back()
、emplace_front()
、emplace()
等。这些函数是 C++ 11 引入的,用于原地构造元素,可以避免不必要的拷贝或移动操作,从而提高性能。
emplace_xxx()
函数的优点
- 效率更高:避免多余的拷贝或移动操作。
- 语法更直观:直接传构造参数,更贴近业务逻辑。
- 构造时即插入:特别适合含有复杂构造函数的对象。
常见容器中的 emplace_xxx()
函数
容器类型 | emplace_xxx() 函数 | 说明 |
---|
vector / deque | emplace_back() | 在末尾就地构造元素 |
list | emplace_back() / emplace_front() | 支持双端插入元素 |
map / set / unordered_map / unordered_set | emplace() | 在合适位置插入新元素 |
stack / queue / priority_queue | emplace() | 等价于对应容器的 emplace_back() 或 emplace_front() |
forward_list | emplace_front() | 在前端插入元素 |
特别注意
如果传给 emplace_xxx()
的参数本身就是一个已经构造好的对象,那它就退化成了 push_xxx()
的效果,失去了原地构造的优势。
案例代码一
这里简单介绍一下 vector
容器的 emplace_back()
函数如何使用,还有它和普通的 push_back()
函数有什么区别。
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
| #include <iostream> #include <vector>
using namespace std;
class Test {
public:
Test(int a) { cout << "Test(int)" << endl; }
Test(int a, int b) { cout << "Test(int, int)" << endl; }
~Test() { cout << "~Test()" << endl; }
Test(const Test &) { cout << "Test(const Test &)" << endl; }
Test(Test &&) { cout << "Test(Test &&)" << endl; }
};
void test01() { cout << "============ test01 ===========" << endl;
Test t1(10); vector<Test> v1; v1.reserve(100);
v1.push_back(t1); v1.emplace_back(t1); }
void test02() { cout << "============ test02 ===========" << endl;
vector<Test> v1; v1.reserve(100);
v1.push_back(Test(20)); v1.emplace_back(Test(20)); }
void test03() { cout << "============ test03 ===========" << endl;
vector<Test> v1; v1.reserve(100);
v1.emplace_back(30); v1.emplace_back(40, 50); }
int main() { test01(); test02(); test03(); return 0; }
|
程序运行输出的结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ============ test01 =========== Test(int) Test(const Test &) Test(const Test &) ~Test() ~Test() ~Test() ============ test02 =========== Test(int) Test(Test &&) ~Test() Test(int) Test(Test &&) ~Test() ~Test() ~Test() ============ test03 =========== Test(int) Test(int, int) ~Test() ~Test()
|
案例代码二
这里将模拟实现 vector
容器的 emplace_back()
函数。值得一提的是,由于篇幅有限,下述代码并没有实现 vector
容器的扩容功能。
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 91 92 93 94 95 96 97 98 99
| #include <iostream> #include <stdexcept>
using namespace std;
template<typename T> struct MyAllocator {
T *allocate(size_t size) { return (T *) malloc(size * sizeof(T)); }
void deallocate(T *p) { free(p); }
template<typename... Types> void construct(T *ptr, Types &&... args) { new(ptr)T(forward<Types>(args)...); }
void destroy(T *p) { p->~T(); }
};
template<typename T, typename Alloc = MyAllocator<T>> class MyVector {
public: MyVector(int size = 10) { _idx = 0; _size = size;
_vec = _allocator.allocate(size);
if (!_vec) { throw bad_alloc(); } }
~MyVector() { for (int i = 0; i < _idx; i++) { _allocator.destroy(_vec + i); }
_allocator.deallocate(_vec); }
MyVector(const MyVector &v) = delete;
MyVector &operator=(const MyVector v) = delete;
template<typename Type> void push_back(Type &&val) { if (_idx >= _size) { throw out_of_range("Vector capacity exceeded."); }
_allocator.construct(_vec + _idx, forward<Type>(val)); _idx++; }
template<typename... Types> void emplace_back(Types &&... args) { if (_idx >= _size) { throw out_of_range("Vector capacity exceeded."); }
_allocator.construct(_vec + _idx, forward<Types>(args)...); _idx++; }
private: T *_vec; size_t _size; size_t _idx; Alloc _allocator;
};
|
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
| class Test {
public:
Test(int a) { cout << "Test(int)" << endl; }
Test(int a, int b) { cout << "Test(int, int)" << endl; }
~Test() { cout << "~Test()" << endl; }
Test(const Test &) { cout << "Test(const Test &)" << endl; }
Test(Test &&) { cout << "Test(Test &&)" << endl; }
};
void test01() { cout << "============ test01 ===========" << endl;
Test t1(10); MyVector<Test> v1;
v1.push_back(t1); v1.emplace_back(t1); }
void test02() { cout << "============ test02 ===========" << endl;
MyVector<Test> v1;
v1.push_back(Test(20)); v1.emplace_back(Test(20)); }
void test03() { cout << "============ test03 ===========" << endl;
MyVector<Test> v1;
v1.emplace_back(30); v1.emplace_back(40, 50); }
int main() { test01(); test02(); test03(); return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ============ test01 =========== Test(int) Test(const Test &) Test(const Test &) ~Test() ~Test() ~Test() ============ test02 =========== Test(int) Test(Test &&) ~Test() Test(int) Test(Test &&) ~Test() ~Test() ~Test() ============ test03 =========== Test(int) Test(int, int) ~Test() ~Test()
|
高频面试题
提示
- 下述面试题都来自 "商汤科技" 的一面,难度属于是简单级别。
智能指针 | 所有权 | 带引用计数 | 适用场景 |
---|
unique_ptr | 独占 | 否 | 资源独占,生命周期明确 |
shared_ptr | 共享 | 是 | 资源共享,生命周期不固定 |
scoped_ptr | 独占 | 否 | 生命周期受限于作用域,适用于简单的场景,避免资源泄漏 |
weak_ptr | 观察 shared_ptr | 否 | 避免 shared_ptr 循环引用 |
auto_ptr | 独占(拷贝时转移) | 否 | ⚠ 已废弃,建议改用 unique_ptr |