容器库——std::vector

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 );countvalue 的副本替换内容。
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元素访问

atoperator[]frontbackdata

  • 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迭代器

begincbeginendcendrbegincrbeginrendcrend

  • 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容量

emptysizemax_sizereservecapacityshrink_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修改器

clearinsertemplaceerasepush_backemplace_backpop_backresizeswap

  • clear 清除内容
函数
void clear();(C++11 前)
void clear() noexcept;(C++11 起)

从容器擦除所有元素。此调用后 size()返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器亦被非法化。

保持 vectorcapacity()不变

  • 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 前插入 valuecount 个副本(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

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值