STL
1.std::vector
1.1成员类型1.2成员函数
1.2.1元素访问1.2.2迭代器1.2.3容量1.2.4修改器
1.std::vector| 定义 | 说明 | |
|---|---|---|
| template< class T, class Allocator = std::allocator > class vector; | std::vector 是封装动态数组的顺序容器。 | |
| namespace pmr { template using vector = std::vector | std::pmr::vector 是使用多态分配器的模板别名。 | (C++17 起) |
vector 的存储是自动管理的,按需扩张收缩。 vector 通常占用多于静态数组的空间,因为要分配更多内存以管理将来的增长。 vector 所用的方式不在每次插入元素时,而只在额外内存耗尽时重分配。分配的内存总量可用capacity() 函数查询。额外内存可通过对 shrink_to_fit()的调用返回给系统。 (C++11 起)
重分配通常是性能上有开销的操作。若元素数量已知,则reserve()函数可用于消除重分配。
1.1成员类型了解即可
1.2成员函数构造函数、析构函数、operator=、assign、get_allocator
operator= :重构的赋值运算符,赋值给容器
get_allocator :返回相关的分配器
assign :将值赋给容器
| 函数 | 说明 | |
|---|---|---|
| void assign( size_type count, const T& value ); | 以 count 份 value 的副本替换内容。 | |
| template< class InputIt > void assign( InputIt first, InputIt last ); | 以范围 [first, last) 中元素的副本替换内容 | |
| void assign( std::initializer_list ilist ); | 以来自 initializer_list ilist 的元素替换内容 | (C++11 起) |
| 参数 | 说明 |
|---|---|
| count | 容器的新大小 |
| value | 用以初始化容器元素的值 |
| first, last | 复制来源元素的范围 |
| ilist | 复制值来源的 initializer_list |
示例
#include1.2.1元素访问#include using namespace std; void assign_demo() { vector characters; vector characters2; characters.assign(5, 'a'); characters2.assign(characters.begin(),characters.begin()+2); for (char c : characters) { cout << c << 'n'; } for (char c : characters2) { cout << c << endl; } initializer_list ilist = {'c','d'}; characters.assign(ilist); for (char c : characters) { cout << c << 'n'; } } int main(){ vector_demo(); return 0; } 输出: a a a a a a a c d
at、operator[]、front、back、data
at :访问指定的元素,同时进行越界检查
| 函数 | 说明 |
|---|---|
| reference at( size_type pos ); | 返回位于指定位置 pos 的元素的引用,有边界检查,(接下行) |
| const_reference at( size_type pos ) const; | 若 pos 不在容器范围内,则抛出 std::out_of_range 类型的异常。返回元素的引用 |
| 参数 | 说明 |
|---|---|
| pos | 要返回的元素的位置 |
operator[] :访问指定的元素
front :访问第一个元素
| 函数 | 说明 |
|---|---|
| reference front(); | 返回到容器首元素的引用,(接下行) |
| const_reference front() const; | 在空容器上对front的调用是未定义的 |
对于容器 c ,表达式c.front() 等价于 *c.begin()
back :访问最后一个元素
| 函数 | 说明 |
|---|---|
| reference back(); | 返回到容器中最后一个元素的引用。 |
| const_reference back() const; | 在空容器上对 back 的调用是未定义的。 |
对于容器 c ,表达式 return c.back();等价于{ auto tmp = c.end(); --tmp; return *tmp; }
data :返回指向内存中数组第一个元素的指针
| 函数 | 说明 | |
|---|---|---|
| T* data() noexcept; | 返回指向作为元素存储工作的底层数组的指针。对于非空容器,返回的指针与首元素地址比较相等。 | (C++11 起) |
| const T* data() const noexcept; | 指针满足范围 [data(); data() + size()) 始终是合法范围,即使容器为空(该情况下 data() 不可解引用)。 | (C++11 起) |
若 size()为 0 ,则 data()可能或可能不返回空指针。
示例
#include1.2.2迭代器#include using namespace std; void visit_demo() { vector numbers{ 2, 4, 6, 8 }; cout << "Second element: " << numbers.at(1) << 'n'; cout << "Second element: " << numbers[1] <<'n'; cout << "First element: " << numbers.front() << endl; cout << "First element: " << *numbers.data() << endl; cout << "Last element: " << numbers.back() << endl; numbers.at(1) = 3; numbers[2] = 5; numbers.front() = 0; *numbers.data() = 1; numbers.back() = 7; cout << "All numbers:"; for (auto i : numbers) { cout << ' ' << i; } cout << 'n'; } int main() { //vector_demo(); visit_demo(); return 0; } 输出: Second element: 4 Second element: 4 First element: 2 First element: 2 Last element: 8 All numbers: 1 3 5 7
begin、cbegin;end、cend;rbegin、crbegin;rend,crend;
begin、cbegin :返回指向容器第一个元素的迭代器
| 函数 | 说明 | |
|---|---|---|
| iterator begin(); | 返回指向容器首元素的迭代器。 | (C++11 前) |
| iterator begin() noexcept; | 若容器为空,则返回的迭代器将等于end()。 | (C++11 起) |
| const_iterator begin() const; | (C++11 前) | |
| const_iterator begin() const noexcept; | (C++11 起) | |
| const_iterator cbegin() const noexcept; | (C++11 起) |
end、cend :返回指向容器尾端的迭代器
| 函数 | 说明 | |
|---|---|---|
| iterator end(); | 返回指向容器末元素后一元素的迭代器。 | (C++11 前) |
| iterator end() noexcept; | 此元素表现为占位符;试图访问它导致未定义行为。 | (C++11 起) |
| const_iterator end() const; | (C++11 前) | |
| const_iterator end() const noexcept; | (C++11 起) | |
| const_iterator cend() const noexcept; | (C++11 起) |
rbegin、crbegin :返回指向容器最后元素的逆向迭代器
| 函数 | 说明 | |
|---|---|---|
| reverse_iterator rbegin(); | 返回指向逆向容器首元素的逆向迭代器。 | (C++11 前) |
| reverse_iterator rbegin() noexcept; | 它对应非逆向容器的末元素。 | (C++11 起) |
| const_reverse_iterator rbegin() const; | (C++11 前) | |
| const_reverse_iterator rbegin() const noexcept; | (C++11 起) | |
| const_reverse_iterator crbegin() const noexcept; | (C++11 起) |
rend、crend :返回指向前端的逆向迭代器
| 函数 | 说明 | |
|---|---|---|
| reverse_iterator rend(); | 返回指向逆向容器末元素后一元素的逆向迭代器。 | (C++11 前) |
| reverse_iterator rend() noexcept; | 它对应非逆向容器首元素的前一元素。 | (C++11 起) |
| const_reverse_iterator rend() const; | 此元素表现为占位符,试图访问它导致未定义行为。 | (C++11 前) |
| const_reverse_iterator rend() const noexcept; | (C++11 起) | |
| const_reverse_iterator crend() const noexcept; | (C++11 起) |
示例
#include1.2.3容量using namespace std; #include #include #include void iterator_demo() { vector ints{ 1, 2, 4, 8, 16 }; vector fruits{ "orange", "apple", "raspberry" }; vector empty; cout << "ints: "; for (vector ::const_iterator it = ints.cbegin(); it != ints.cend(); it++) cout<< *it << " "; cout << endl; cout << "reverse of ints:"; for (auto it = ints.rbegin(); it != ints.rend(); ++it) cout << *it << " "; cout << endl; // 打印 vector fruits 中的首个水果,而不检查是否有一个。 cout << "First fruit: " << *fruits.begin() << "n"; if (empty.begin() == empty.end()) cout << "vector 'empty' is indeed empty.n"; } int main() { //vector_demo(); //visit_demo(); iterator_demo(); return 0; } 输出: ints: 1 2 4 8 16 reverse of ints:16 8 4 2 1 First fruit: orange vector 'empty' is indeed empty.
empty、size、max_size、reserve、capacity、shrink_to_fit
empty :检查容器是否为空
| 函数 | 说明 | |
|---|---|---|
| bool empty() const; | 检查容器是否无元素,即是否 begin() == end() 。 | (C++11 前) |
| bool empty() const noexcept; | (C++11 起) (C++20 前) | |
| [[nodiscard]] bool empty() const noexcept; | (C++20 起) |
size :返回容纳的元素数
| 函数 | 说明 | |
|---|---|---|
| size_type size() const; | 返回容器中的元素数,即 std::distance(begin(), end()) 。 | (C++11 前) |
| size_type size() const noexcept; | (C++11 起) |
max_size :返回可容纳的最大元素数
| 函数 | 说明 | |
|---|---|---|
| size_type max_size() const; | 返回根据系统或库实现限制的容器可保有的元素最大数量 | (C++11 前) |
| size_type max_size() const noexcept; | ,即对于最大容器的 std::distance(begin(), end()) 。 | (C++11 起) |
此值通常反映容器大小上的理论极限,至多为std::numeric_limits
reserve :预留存储空间
| 函数 | 说明 |
|---|---|
| void reserve( size_type new_cap ); | 增加 vector 的容量到大于或等于 new_cap 的值。若 new_cap 大于当前的capacity() ,则分配新存储,否则该方法不做任何事。 |
reserve() 不更改 vector 的 size 。
若 new_cap 大于 capacity(),则所有迭代器,包含尾后迭代器和所有元素的引用都被非法化。否则,没有迭代器或引用被非法化。
不能用 reserve() 减少容器容量。为该目的提供的是shrink_to_fit()。
正确使用 reserve() 能避免不必要的分配,但不适当地使用 reserve() (例如在每次 push_back()调用前调用它)可能会实际增加重分配的数量(通过导致容量线性而非指数增长)并导致计算复杂度增加,性能下降。
capacity :返回当前存储空间能够容纳的元素数
| 函数 | 说明 | |
|---|---|---|
| size_type capacity() const; | 返回容器当前已为之分配空间的元素数。 | (C++11 前) |
| size_type capacity() const noexcept; | (C++11 起) |
shrink_to_fit :通过释放未使用的内存减少内存的使用
| 函数 | 说明 | |
|---|---|---|
| void shrink_to_fit(); | 请求移除未使用的容量。 | (C++11 起) |
它是减少capacity()到 size()非强制性请求。请求是否达成依赖于实现。
若发生重分配,则所有迭代器,包含尾后迭代器,和所有到元素的引用都被非法化。若不发生重分配,则没有迭代器或引用被非法化。
示例
#includeusing namespace std; #include #include #include void capacity_demo() { cout << boolalpha;//启用流 str 中的 boolalpha 标志 vector numbers; cout << "Initially, numbers.empty(): " << numbers.empty() << 'n'; numbers.push_back(42); cout << "After adding elements, numbers.empty(): " << numbers.empty() << 'n'; vector nums{ 1, 3, 5, 7 }; cout << "nums contains " << nums.size() << " elements.n"; vector s; cout << "Maximum size of a 'vector' is " << s.max_size() << "n"; int sz = 100; cout << "not using reserve: n"; vector v1; v1.push_back(10); v1.push_back(10); cout << sizeof(v1) << " bytes" << endl; cout << "Capacity is " << v1.capacity() << endl; std::cout << "using reserve: n"; v1.reserve(sz); cout << sizeof(v1) << " bytes" << endl; cout << "Capacity is " < 1.2.4修改器 clear、insert、emplace、erase、push_back、emplace_back、pop_back、resize、swap
clear 清除内容
函数 void clear(); (C++11 前) void clear() noexcept; (C++11 起) 从容器擦除所有元素。此调用后 size()返回零。
非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器亦被非法化。
保持 vector 的capacity()不变
insert 插入元素
函数 说明 iterator insert( iterator pos, const T& value ); 在 pos 前插入 value 。 (C++11 前) iterator insert( const_iterator pos, const T& value ); (C++11 起) iterator insert( const_iterator pos, T&& value ); (C++11 起) void insert( iterator pos, size_type count, const T& value ); 在 pos 前插入 value 的 count 个副本 (C++11 前) iterator insert( const_iterator pos, size_type count, const T& value ); (C++11 起) template< class InputIt > void insert( iterator pos, InputIt first, InputIt last); 在 pos 前插入来自范围 [first, last) 的元素 (C++11 前) template< class InputIt > iterator insert( const_iterator pos, InputIt first, InputIt last ); (C++11 起) iterator insert( const_iterator pos, std::initializer_list ilist ); 在 pos 前插入来自 initializer_list ilist 的元素。 (C++11 起) 插入元素到容器中的指定位置。
若新size()大于旧capacity()则导致重分配。 若新的size()大于capacity(),则所有迭代器和引用都被非法化。否则,仅在插入点前的迭代器和引用保持合法。尾后迭代器亦被非法化。
emplace 原位构造元素
函数 template< class… Args > iterator emplace( const_iterator pos, Args&&… args ); 直接于 pos 前插入元素到容器中。 (C++11 起) 直接于 pos 前插入元素到容器中。通过std::allocator_traits::construct构造元素,它典型地用布置 new 在容器所提供的位置原位构造元素。将参数 args... 作为 std::forward)(args)… 转发给构造函数。
若新的 size()大于capacity() ,则所有迭代器和引用都被非法化。否则,仅在插入点前的迭代器和引用保持合法。尾后迭代器亦被非法化。
erase 擦除元素
函数 说明 iterator erase( iterator pos ); 移除位于 pos 的元素。 (C++11 前) iterator erase( const_iterator pos ); (C++11 起) iterator erase( iterator first, iterator last ); 移除范围 [first; last) 中的元素。 (C++11 前) iterator erase( const_iterator first, const_iterator last ); (C++11 起) 从容器擦除指定的元素。
非法化位于擦除点或之后的迭代器,包含end()迭代器。
迭代器 pos 必须合法且可解引用。从而不能以 end()迭代器(合法,但不可解引用)为 pos 的值。
若 first==last 则迭代器 first 不必可解引用:擦除空范围是无操作。
push_back 将元素添加到容器尾
函数 说明 void push_back( const T& value ); 初始化新元素为 value 的副本。 void push_back( T&& value ); 移动 value 进新元素。 (C++11 起) 后附给定元素 value 到容器尾。
若新的size()大于capacity(),则所有迭代器和引用(包含尾后迭代器)都被非法化。否则仅尾后迭代器被非法化。
emplace_back 在容器末尾就地构造元素
函数 template< class… Args > void emplace_back( Args&&… args ); (C++11 起) (C++17 前) template< class… Args > reference emplace_back( Args&&… args ); (C++17 起) 添加新元素到容器尾。元素通过std::allocator_traits::construct 构造,它典型地用布置 new 于容器所提供的位置原位构造元素。参数 args... 以std::forward(args)… 转发到构造函数。
若新的size()大于capacity(),则所有迭代器和引用(包含尾后迭代器)都被非法化。否则仅尾后迭代器被非法化。
emplace_back 可避免用 push_back 时的额外复制或移动操作
pop_back 移除末元素
函数 void pop_back(); 移除容器的最末元素。 在空容器上调用 pop_back 是未定义的。
非法化指向末元素的迭代器和引用,以及end()迭代器。
resize 改变容器中可存储元素的个数
函数 void resize( size_type count ); (1) (C++11 起) void resize( size_type count, const value_type& value ); (2) (C++11 起) 重设容器大小以容纳 count 个元素。
若当前大小 大于 count ,则减小容器为其首 count 个元素。
若当前大小 小于 count ,则后附额外元素,并以 value 的副本初始化。(C++11 前)
若当前大小 小于 count ,
1) 则后附额外的默认插入的元素
2) 则后附额外的 value 的副本(C++11 起)
swap 交换内容
函数 说明 void swap( vector& other ); 将内容与 other 的交换。 (C++17 前) void swap( vector& other ) noexcept(); 不在单个元素上调用任何移动、复制或交换操作。 (C++17 起) 所有迭代器和引用保持合法。尾后迭代器被非法化。
若 std::allocator_traits::propagate_on_container_swap::value 为 true ,则用非成员 swap 的非限定调用交换分配器。否则,不交换它们(且若 get_allocator() != other.get_allocator() ,则行为未定义)。(C++11 起)
示例
#includeusing namespace std; #include #include #include void revise_demo() { vector vec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; print_vec(vec); vec.erase(vec.begin());//1 print_vec(vec); vec.erase(vec.begin() + 2, vec.begin() + 5);//2 print_vec(vec); vec.pop_back(); cout << "After using pop_back:" ; print_vec(vec); vec.clear(); cout << "After using clear:"; print_vec(vec); vec = vector (3, 100); auto it = vec.begin(); it = vec.insert(it, 200);//在it位置插入200,返回begin() vec.insert(it, 2, 300);//在it位置插入两个300 print_vec(vec); // "it" 不再合法,获取新值: it = vec.begin(); vector vec2(2, 400); vec.insert(it + 2, vec2.begin(), vec2.end());//在it+2的位置插入vec2 print_vec(vec); int arr[] = { 501,502,503 }; vec.insert(vec.begin(), arr, arr + 3);//在begin()处插入arr print_vec(vec); struct President { string name; string country; int year; President(string p_name, string p_country, int p_year) : name(move(p_name)), country(move(p_country)), year(p_year) { cout << "I am being constructed.n";//构造函数 } President(President&& other) : name(move(other.name)), country(move(other.country)), year(other.year) { cout << "I am being moved.n";//拷贝构造函数 } President& operator=(const President& other) = default; }; vector elections; cout << "emplace_back:n"; elections.emplace_back("Nelson Mandela", "South Africa", 1994);//不会调用拷贝构造函数 vector reElections; cout << "npush_back:n"; reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));//会调用拷贝构造函数 vector c = { 1, 2, 3 }; vector c2 = { 4,5,6 }; cout << "nThe vector holds: "; print_vec(c); c.resize(5); cout << "After resize up to 5: "; print_vec(c); c.resize(2); cout << "After resize down to 2: "; print_vec(c); c.swap(c2); cout << "After swap with c2: "; print_vec(c); } int main() { //vector_demo(); //visit_demo(); //iterator_demo(); //capacity_demo(); revise_demo(); return 0; } 输出: 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 6 7 8 9 After using pop_back: 1 2 6 7 8 After using clear: 300 300 200 100 100 100 300 300 400 400 200 100 100 100 501 502 503 300 300 400 400 200 100 100 100 emplace_back: I am being constructed. push_back: I am being constructed. I am being moved. The vector holds: 1 2 3 After resize up to 5: 1 2 3 0 0 After resize down to 2: 1 2 After swap with c2: 4 5 6



