std::array
看到这个容器的时候肯定会出现这样的问题:
为什么要引入 std::array
而不是直接使用 std::vector
?
已经有了传统数组,为什么要用 std::array
?
先回答第一个问题,与 std::vector
不同,std::array
对象的大小是固定的,如果容器大小是固定的,那么可以优先考虑使用 std::array
容器。另外由于 std::vector
是自动扩容的,当存入大量的数据后,并且对容器进行了删除操作, 容器并不会自动归还被删除元素相应的内存,这时候就需要手动运行 shrink_to_fit()
释放这部分内存。
std::vector<int> v; std::cout << "size:" << v.size() << std::endl; // 输出 0 std::cout << "capacity:" << v.capacity() << std::endl; // 输出 0
// 如下可看出 std::vector 的存储是自动管理的,按需自动扩张 // 但是如果空间不足,需要重新分配更多内存,而重分配内存通常是性能上有开销的操作 v.push_back(1); v.push_back(2); v.push_back(3); std::cout << "size:" << v.size() << std::endl; // 输出 3 std::cout << "capacity:" << v.capacity() << std::endl; // 输出 4
// 这里的自动扩张逻辑与 Golang 的 slice 很像 v.push_back(4); v.push_back(5); std::cout << "size:" << v.size() << std::endl; // 输出 5 std::cout << "capacity:" << v.capacity() << std::endl; // 输出 8
// 如下可看出容器虽然清空了元素,但是被清空元素的内存并没有归还 v.clear(); std::cout << "size:" << v.size() << std::endl; // 输出 0 std::cout << "capacity:" << v.capacity() << std::endl; // 输出 8
// 额外内存可通过 shrink_to_fit() 调用返回给系统 v.shrink_to_fit(); std::cout << "size:" << v.size() << std::endl; // 输出 0 std::cout << "capacity:" << v.capacity() << std::endl; // 输出 0
|
而第二个问题就更加简单,使用 std::array
能够让代码变得更加“现代化”,而且封装了一些操作函数,比如获取数组大小以及检查是否非空,同时还能够友好的使用标准库中的容器算法,比如 std::sort
。
使用 std::array
很简单,只需指定其类型和大小即可:
std::array<int, 4> arr = {1, 2, 3, 4};
arr.empty(); // 检查容器是否为空 arr.size(); // 返回容纳的元素数
// 迭代器支持 for (auto &i : arr) { // ... }
// 用 lambda 表达式排序 std::sort(arr.begin(), arr.end(), [](int a, int b) { return b < a; });
// 数组大小参数必须是常量表达式 constexpr int len = 4; std::array<int, len> arr = {1, 2, 3, 4};
// 非法,不同于 C 风格数组,std::array 不会自动退化成 T* // int *arr_p = arr;
|
当我们开始用上了 std::array
时,难免会遇到要将其兼容 C 风格的接口,这里有三种做法:
void foo(int *p, int len) { return; }
std::array<int, 4> arr = {1,2,3,4};
// C 风格接口传参 // foo(arr, arr.size()); // 非法, 无法隐式转换 foo(&arr[0], arr.size()); foo(arr.data(), arr.size());
// 使用 `std::sort` std::sort(arr.begin(), arr.end());
|
std::forward_list
std::forward_list
是一个列表容器,使用方法和 std::list
基本类似,因此我们就不花费篇幅进行介绍了。
需要知道的是,和 std::list
的双向链表的实现不同,std::forward_list
使用单向链表进行实现, 提供了 O(1)
复杂度的元素插入,不支持快速随机访问(这也是链表的特点), 也是标准库容器中唯一一个不提供 size()
方法的容器。当不需要双向迭代时,具有比 std::list
更高的空间利用率。
来源:https://changkun.de/modern-cpp/zh-cn/04-containers/
C++ 面试必问:深入理解虚函数表
很多人搞不清 C++ 中的 delete 和 delete[ ] 的区别
看懂别人的代码,总得懂点 C++ lambda 表达式吧
Java、C++ 内存模型都不知道,还敢说自己是高级工程师?
C++ std::thread 必须要熟悉的几个知识点
现代 C++ 并发编程基础
现代 C++ 智能指针使用入门
c++ thread join 和 detach 到底有什么区别?
C++ 面试八股文:list、vector、deque 比较
C++经典面试题(最全,面中率最高)
C++ STL deque 容器底层实现原理(深度剖析)
STL vector push_back 和 emplace_back 区别
了解 C++ 多态与虚函数表