mirror of
https://github.com/changkun/modern-cpp-tutorial.git
synced 2025-12-17 04:34:40 +03:00
update: ch04, std::array section (#57)
* doc(04): update std::array section * doc(04): update desc * doc(04): update std::array * doc(04): remove unprint symbols * doc(04): update
This commit is contained in:
@@ -19,17 +19,65 @@ order: 4
|
||||
1. 为什么要引入 `std::array` 而不是直接使用 `std::vector`?
|
||||
2. 已经有了传统数组,为什么要用 `std::array`?
|
||||
|
||||
先回答第一个问题,`std::vector` 太强大了,以至于我们没有必要为了去敲碎一个鸡蛋而用一个钉锤。使用 `std::array` 保存在栈内存中,相比堆内存中的 `std::vector`,我们就能够灵活的访问这里面的元素,从而获得更高的性能;同时正是由于其堆内存存储的特性,有些时候我们还需要自己负责释放这些资源。
|
||||
|
||||
而第二个问题就更加简单,使用`std::array`能够让代码变得更加现代,且封装了一些操作函数,同时还能够友好的使用标准库中的容器算法等等,比如 `std::sort`。
|
||||
|
||||
`std::array` 会在编译时创建一个固定大小的数组,`std::array` 不能够被隐式的转换成指针,使用 `std::array` 很简单,只需指定其类型和大小即可:
|
||||
先回答第一个问题,与 `std::vector` 不同,`std::array` 对象的大小是固定的,如果容器大小是固定的,那么可以优先考虑使用 `std::array` 容器。另外由于 `std::vector` 是自动扩容的,当存入大量的数据后,并且对容器进行了删除操作,容器并不会自动归还被删除元素相应的内存,这时候就需要手动运行 `shrink_to_fit()` 释放这部分内存。
|
||||
|
||||
```cpp
|
||||
std::array<int, 4> arr= {1,2,3,4};
|
||||
std::vector<int> v;
|
||||
std::cout << "size:" << v.size() << std::endl; // 输出 0
|
||||
std::cout << "capacity:" << v.capacity() << std::endl; // 输出 0
|
||||
|
||||
int len = 4;
|
||||
std::array<int, len> arr = {1,2,3,4}; // 非法, 数组大小参数必须是常量表达式
|
||||
// 如下可看出 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` 很简单,只需指定其类型和大小即可:
|
||||
|
||||
```cpp
|
||||
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 风格的接口,这里有三种做法:
|
||||
|
||||
Reference in New Issue
Block a user