cpp容器——vector
·
什么是容器

- 通过cppreference的介绍,容器是一种通用的类模板和算法的集合,可以允许程序员快速的实现数据结构。
c++11之前只有两种容器(序列和关联),c++11后多了无序关联容器,今天我们介绍序列式容器——vector
基本定义

- 我们要讲的是第一个,他接受两个模板参数,第一个是
vector存储的数据类型,另一个是分配器,vector的底层是动态数组,用来分配空间。简单介绍一下另一个vector, 它的第二个参数是std::pmr::polymorphic_allocato,它是C++17引入的一个运行时可切换的内存分配器,你可以在运行时决定:用普通堆、内存池、栈上buffer、共享内存分配内存
成员类型
- 这里是对模板参数进行了封装,提供了一些比较明确的类型

构造函数
- 这里包括了类的默认构造、拷贝构造、有参构造等函数

- 使用示例
#include <vector>
int main() {
// 1. 默认构造函数
std::vector<int> v1; // 空 vector
// 2. 填充构造函数:包含 10 个元素,每个元素值为 42
std::vector<int> v2(10, 42);
// 3. 范围构造函数:使用数组迭代器构造
int arr[] = {1, 2, 3, 4, 5};
std::vector<int> v3(std::begin(arr), std::end(arr));
// 4. 拷贝构造函数:复制 v3 的内容
std::vector<int> v4(v3);
// 5. 移动构造函数:将 v4 的资源转移给 v5
std::vector<int> v5(std::move(v4));
// 6. initializer_list 构造函数:使用花括号列表初始化
std::vector<int> v6{10, 20, 30, 40};
// 7. 分配器构造函数(较少单独使用,此处仅作示意)
// std::allocator<int> alloc;
// std::vector<int> v7(alloc);
return 0;
}
成员函数
元素访问
at用来访问指定index的元素,访问前会进行越界检查,越界会抛异常;operator[]可以使用[]访问元素;front可以直接访问容器首个元素;back访问容器最后一个有效的元素;data用来获取vector底层动态数组的原始指针
- 使用示例
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{10, 20, 30, 40, 50};
// 1. operator[]
std::cout << "v[2] = " << v[2] << "\n"; // 不检查越界
// 2. at(带边界检查)
try {
std::cout << "v.at(3) = " << v.at(3) << "\n";
// std::cout << v.at(10); // 会抛异常
} catch (const std::out_of_range& e) {
std::cout << "out_of_range: " << e.what() << "\n";
}
// 3. front(第一个元素)
std::cout << "front = " << v.front() << "\n";
// 4. back(最后一个元素)
std::cout << "back = " << v.back() << "\n";
// 5. data(底层连续内存)
int* ptr = v.data();
std::cout << "data[0] = " << *ptr << "\n";
// 用 data() 遍历
std::cout << "Using data(): ";
for (size_t i = 0; i < v.size(); ++i)
{
std::cout << *(ptr + i) << " ";
}
std::cout << "\n";
return 0;
}
迭代器
- 迭代器可以用来访问元素,
cpp11引入了范围for,这个特性需要支持类支持迭代器
- 使用示例
vector<int> vec{1,2,3,4,5}
for (auto v:vec)
{
std::cout << v << " ";
}
for (auto it = vec.begin(); it != vec.end(); ++it)
std::cout << v << " ";
- 范围for会被转换成下面这样
std::vector<int, std::allocator<int> > vec = std::vector<int, std::allocator<int> >{std::initializer_list<int>{1, 2, 3, 4, 5}, std::allocator<int>()};
{
std::vector<int, std::allocator<int> > & __range1 = vec;
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > __begin1 = __range1.begin();
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > __end1 = __range1.end();
for(; __gnu_cxx::operator!=(__begin1, __end1); __begin1.operator++()) {
int v = __begin1.operator*();
std::operator<<(std::cout.operator<<(v), " ");
}
}
容量
empty函数判断容器是否有有效的元素;size返回容器中有效元素的个数;max_size返回当前系统可以容纳的最大元素数量;reserve用来预分配容器容量;shrink_to_fit用来对容器进行缩容;具体行为依赖编译器实现;clear函数不会改变capacity
- 使用示例
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
// 1. empty
std::cout << "empty: " << std::boolalpha << v.empty() << "\n";
// 2. reserve(预分配空间)
v.reserve(10);
std::cout << "after reserve(10): capacity = " << v.capacity() << "\n";
// 插入元素
for (int i = 1; i <= 5; ++i)
{
v.push_back(i);
}
// 3. size
std::cout << "size: " << v.size() << "\n";
// 4. capacity
std::cout << "capacity: " << v.capacity() << "\n";
// 5. max_size
std::cout << "max_size: " << v.max_size() << "\n";
// 6. shrink_to_fit(请求释放多余空间)
v.shrink_to_fit();
std::cout << "after shrink_to_fit:\n";
std::cout << "size: " << v.size() << "\n";
std::cout << "capacity: " << v.capacity() << "\n";
// 再清空元素
v.clear();
std::cout << "after clear:\n";
std::cout << "empty: " << v.empty() << "\n";
std::cout << "size: " << v.size() << "\n";
std::cout << "capacity (still there): " << v.capacity() << "\n";
return 0;
}
修改操作
clear函数只会清空元素,不会改变数量;insert可以在指定位置插入一个或一段区间的元素,返回插入的第一个元素的迭代器;emplace可以原地构造一个元素并插入指定位置;push_back在容器末尾插入一个元素;emplace_back原地构造一个元素并插入末尾;当传入临时对象时,emplace_back会比push_back高效,如果是一个已经构造好的元素,并不能确定谁更高效;pop_back移除末尾的元素;resize可以重新指定容器的大小,多余的元素以对应类型的默认值填充;swap可以用来交换两个容器的内容emplace_back更适合传需要构造的参数,如果是一个构造好的对象,优先使用push_back;
- 示例
#include <iostream>
#include <vector>
void print(const std::vector<int>& v)
{
for (auto x : v) std::cout << x << " ";
std::cout << "\n";
}
int main()
{
std::vector<int> v{1, 2, 3};
// 1. push_back
v.push_back(4); // [1 2 3 4]
// 2. emplace_back(就地构造)
v.emplace_back(5); // [1 2 3 4 5]
print(v);
// 3. insert(在指定位置插入)
v.insert(v.begin() + 1, 99); // [1 99 2 3 4 5]
print(v);
// 4. insert range(用传统方式模拟)
std::vector<int> other{7, 8, 9};
v.insert(v.end(), other.begin(), other.end()); // [1 99 2 3 4 5 7 8 9]
print(v);
// 5. emplace(在中间构造)
v.emplace(v.begin() + 2, 88); // [1 99 88 2 3 4 5 7 8 9]
print(v);
// 6. erase(删除元素)
v.erase(v.begin() + 1); // 删除 99
print(v);
// 删除区间
v.erase(v.begin() + 2, v.begin() + 4);
print(v);
// 7. pop_back
v.pop_back();
print(v);
// 8. resize
v.resize(5); // 截断或补默认值
print(v);
v.resize(8, 100); // 不够就补 100
print(v);
// 9. swap
std::vector<int> v2{1000, 2000};
v.swap(v2);
std::cout << "v: ";
print(v);
std::cout << "v2: ";
print(v2);
// 10. clear
v.clear();
std::cout << "v after clear: ";
print(v);
return 0;
}
这篇文章就写到这里了,如果觉得写的还不错,欢迎点赞关注,如果有错误还请批评指正
更多推荐




所有评论(0)