STL
1.std::vector
定义 | 说明 | |
---|---|---|
template< class T, class Allocator = std::allocator > class vector; | std::vector 是封装动态数组的顺序容器。 | |
namespace pmr { template using vector = std::vector<T, std::pmr::polymorphic_allocator>; } | 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 |
示例
#include <iostream>
#include <vector>
using namespace std;
void assign_demo()
{
vector<char> characters;
vector<char> 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<char> 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
1.2.1元素访问
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()
可能或可能不返回空指针。
示例
#include <iostream>
#include <vector>
using namespace std;
void visit_demo() {
vector<int> 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
1.2.2迭代器
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 起) |
示例
#include <iostream>
using namespace std;
#include <vector>
#include <iterator>
#include <string>
void iterator_demo() {
vector<int> ints{ 1, 2, 4, 8, 16 };
vector<string> fruits{ "orange", "apple", "raspberry" };
vector<char> empty;
cout << "ints: ";
for (vector<int>::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.
1.2.3容量
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<difference_type>::max()
。运行时,可用 RAM 总量可能会限制容器大小到小于 max_size()
的值。
- 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()
非强制性请求。请求是否达成依赖于实现。
若发生重分配,则所有迭代器,包含尾后迭代器,和所有到元素的引用都被非法化。若不发生重分配,则没有迭代器或引用被非法化。
示例
#include <iostream>
using namespace std;
#include <vector>
#include <iterator>
#include <string>
void capacity_demo() {
cout << boolalpha;//启用流 str 中的 boolalpha 标志
vector<int> numbers;
cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';
numbers.push_back(42);
cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
vector<int> nums{ 1, 3, 5, 7 };
cout << "nums contains " << nums.size() << " elements.\n";
vector<char> s;
cout << "Maximum size of a 'vector' is " << s.max_size() << "\n";
int sz = 100;
cout << "not using reserve: \n";
vector<int> 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 " <<v1.capacity() << endl;
v1.shrink_to_fit();
cout << "Capacity after shrink_to_fit() is " << v1.capacity();
}
int main() {
//vector_demo();
//visit_demo();
//iterator_demo();
capacity_demo();
return 0;
}
输出:
Initially, numbers.empty(): true
After adding elements, numbers.empty(): false
nums contains 4 elements.
Maximum size of a 'vector' is 2147483647
not using reserve:
16 bytes
Capacity is 2
using reserve:
16 bytes
Capacity is 100
Capacity after shrink_to_fit() is 2
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(/* see below */); | 不在单个元素上调用任何移动、复制或交换操作。 | (C++17 起) |
所有迭代器和引用保持合法。尾后迭代器被非法化。
若 std::allocator_traits<allocator_type>::propagate_on_container_swap::value 为 true ,则用非成员 swap
的非限定调用交换分配器。否则,不交换它们(且若 get_allocator() != other.get_allocator() ,则行为未定义)。(C++11 起)
示例
#include <iostream>
using namespace std;
#include <vector>
#include <iterator>
#include <string>
void revise_demo() {
vector<int> 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<int>(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<int> 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<President> elections;
cout << "emplace_back:\n";
elections.emplace_back("Nelson Mandela", "South Africa", 1994);//不会调用拷贝构造函数
vector<President> reElections;
cout << "\npush_back:\n";
reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));//会调用拷贝构造函数
vector<int> c = { 1, 2, 3 };
vector<int> 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