[C++] std::vector

向量是表示可以动态改变大小的数组的序列容器。

就像数组一样,向量为它们的元素使用连续的存储位置,这意味着它们的元素也可以使用对其元素的常规指针的偏移进行访问,并且与数组中一样有效。但是与数组不同的是,它们的大小可以动态地改变,其存储由容器自动处理。

在内部,向量使用动态分配的数组来存储它们的元素。这个数组可能需要重新分配,以便在插入新元素时增加大小,这意味着分配一个新数组并将所有元素移动到它。这在处理时间方面是一项相对昂贵的任务,因此,每次向容器添加元素时,向量不会重新分配。

相反,向量容器可以分配一些额外的存储以适应可能的增长,并且因此容器可以具有大于容纳其元素(即其大小)严格需要的存储空间的实际容量。

库可以实现不同的增长策略,以平衡内存使用和重新分配。但在任何情况下,重新分配只应该以对数增长的大小间隔发生,以便在向量的末端插入单个元素可以提供有平摊的恒定时间复杂度(见push_back)。

因此,与数组相比,向量消耗更多的内存,以便有效地管理存储和动态增长的能力。

与其他动态序列容器(deques,lists和forward_lists)相比,向量非常有效地访问其元素(就像数组),并且相对有效地从其结尾添加或删除元素。

对于涉及在不同于其他位置的位置插入或删除元素的操作,它们执行得比其他位置更差。

如果容器为空,则begin()和end()返回的是同一个迭代器,都是尾后迭代器

迭代器失效:改变vector对象容量的操作都会导致迭代器失效

迭代器不能相加。

迭代器相减的结果类型是difference::type,是一个有符号的数。

特性

有序

序列容器中的元素以严格的线性顺序排列。单个元素按其顺序通过其位置访问。

动态数组

允许直接访问序列中的任何元素,甚至通过指针算术,并在序列结尾提供相对快速的添加/删除元素。

自动存储

容器使用allocator对象动态处理其存储需求。

vector (constructor)

default (1)

explicit vector (const allocator_type& alloc = allocator_type());

fill (2)

explicit vector (size_type n);

vector (size_type n, const value_type& val,

const allocator_type& alloc = allocator_type());

range (3)

template <class InputIterator>

vector (InputIterator first, InputIterator last,

const allocator_type& alloc = allocator_type());

copy (4)

vector (const vector& x);

vector (const vector& x, const allocator_type& alloc);

move (5)

vector (vector&& x);

vector (vector&& x, const allocator_type& alloc);

initializer list (6)

vector (initializer_list<value_type> il,

const allocator_type& alloc = allocator_type());

代码举例

#include <iostream>
#include <vector>

int main() {
    std::vector<int> first; // default(1)
    std::vector<int> second(4, 100); // fill(2)
    std::vector<int> third(second.begin(), second.end()); // range(3)
    std::vector<int> fourth(third); // copy(4)

    // the iterator constructor can also be used to construct from arrays:
    int myints[] = {16,2,77,29};
    std::vector<int> fifth(myints, myints + sizeof(myints) / sizeof(int));

    std::cout << "The contents of fifth are:";
    for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';

    return 0;
}    
Output:
The contents of fifth are: 16 2 77 29

std::vector::operator=

将新内容分配给容器,替换其当前内容,并相应地修改其大小。

任何在容器中的元素被访问前都会陪分配或销毁。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> foo(3, 0);
    std::vector<int> bar(5, 0);

    bar = foo;
    foo = std::vector<int>();

    std::cout << "Size of foo: " << int(foo.size()) << '\n';
    std::cout << "Size of var: " << int(bar.size()) << '\n';
    return 0;
}
Output:
Size of foo: 0
Size of bar: 3

std::vector::assign

将新内容分配给向量,替换其当前内容,并相应地修改其大小。

在调用之前,容器中保存的任何元素都被销毁,并被新构造的元素替换(元素的赋值不发生)。

这将导致所分配的存储空间的自动重新分配,当且仅当新的向量大小超过当前的向量容量。

// vector assign
#include <iostream>
#include <vector>

int main () {
    std::vector<int> first;
    std::vector<int> second;
    std::vector<int> third;

    first.assign(7, 100); // 7 ints with a value of 100

    std::vector<int>::iterator it;
    it=first.begin() + 1;

    second.assign(it,first.end() - 1); // the 5 central values of first

    int myints[] = {1776, 7, 4};
    third.assign(myints, myints + 3); // assigning from array.

    std::cout << "Size of first: " << int (first.size()) << '\n';
    std::cout << "Size of second: " << int (second.size()) << '\n';
    std::cout << "Size of third: " << int (third.size()) << '\n';
    return 0;
}
Output:
Size of first: 7
Size of second: 5
Size of third: 3

operator= 与 assign 区别

相同点:operator=与assign都是释放原来的内存空间,并分配新的内存空间

不同点:assign返回值为none  operator=返回值为*this

Vector Iterators

begin()  Return iterator to beginning

end()   Return iterator to end

rbegin()  Return reverse iterator to reverse beginning

rend()    Return reverse iterator to reverse end

cbegin()  Return const_iterator to beginning

cend()   Return const_iterator to end

crbegin()  Return const_reverse_iterator to reverse beginning

crend()   Return const_reverse_iterator to reverse end

std::vector::cbegin/cend

返回指向容器中首元素的迭代器

返回指向容器中尾元素下一个元素的迭代器

返回的const_iterator所指的对象值不能改变。

// vector::cbegin/cend
#include <iostream>
#include <vector>

int main () {
    std::vector<int> myvector = {10, 20, 30, 40, 50};

    std::cout << "myvector contains:";

    for (auto it = myvector.cbegin(); it != myvector.cend(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';

    return 0;
}
Output:
myvector contains: 10 20 30 40 50

std::vector::size    Return size

std::vector::capacity  Return size of allocated storage capacity

std::vector::max_size  Return maximum size

// comparing size, capacity and max_size
#include <iostream>
#include <vector>

int main ()
{
    std::vector<int> myvector;

    // set some content in the vector:
    for (int i=0; i < 100; i++) 
  myvector.push_back(i);
std::cout << "size: " << myvector.size() << "\n"; std::cout << "capacity: " << myvector.capacity() << "\n"; std::cout << "max_size: " << myvector.max_size() << "\n"; return 0; }
A possible output for this program could be:
size: 100
capacity: 128
max_size: 1073741823

size 返回实际容量

capacity 返回默认容量

max_size 返回向量可以容纳的最大元素数,这个max_size由系统或库限制。但容器绝对不能保证能够达到该尺寸,因为在达到该大小之前的任何时间点仍然无法分配存储空间。

std::vector::empty  Test whether vector is empty

std::vector::operator[]  

Return a reference to the element at position n in the vector container.

// vector::operator[]
#include <iostream>
#include <vector>

int main ()
{
    std::vector<int> myvector (10);   // 10 zero-initialized elements

    std::vector<int>::size_type sz = myvector.size();

    // assign some values:
    for (unsigned i = 0; i < sz; i++) 
  myvector[i] = i; // reverse vector using operator[]: for (unsigned i = 0; i < sz / 2; i++) { int temp; temp = myvector[sz - 1 - i]; myvector[sz - 1 - i] = myvector[i]; myvector[i] = temp; } std::cout << "myvector contains:"; for (unsigned i = 0; i < sz; i++) std::cout << ' ' << myvector[i]; std::cout << '\n'; return 0; }
Output:
myvector contains: 9 8 7 6 5 4 3 2 1 0

std::vector::at   Access element

std::vector::front  Access first element

std::vector::back  Access last element.

std::vector::data   Access data

Returns a direct pointer to the memory array used internally by the vector to store its owned elements.

// vector::data
#include <iostream>
#include <vector>

int main() {
    std::vector<int> myvector(5);

    int* p = myvector.data();

    *p = 10;
    ++p;
    *p = 20;
    p[2] = 100;

    std::cout << "myvector contains:";
    for (unsigned i = 0; i < myvector.size(); ++i)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';

    return 0;
}
myvector contains: 10 20 0 100 0

std::vector::push_back  Add element at the end

std::vector::pop_back   Delete last element

std::vector::insert     Insert elements

通过在指定位置的元素之前插入新元素来扩展向量,通过插入的元素数量有效地增加容器大小。

这将导致所分配的存储空间的自动重新分配,当且仅当新的向量大小超过当前的向量容量。

由于向量使用数组作为其底层存储,因此将元素插入到向量端以外的位置会导致容器将位置之后的所有元素重新定位到新位置。与通过其他类型的序列容器(例如list或forward_list)执行相同操作的操作相比,这通常是一个低效的操作。

// inserting into a vector
#include <iostream>
#include <vector>

int main() {
    std::vector<int> myvector(3, 100);
    std::vector<int>::iterator it;

    it = myvector.begin();
    it = myvector.insert(it, 200);

    myvector.insert(it, 2, 300);
    
    // "it" no longer valid, get a new one.
    it = myvector.begin();

    std::vector<int> anothervector(2, 400);
    myvector.insert(it + 2, anothervector.begin(), anothervector.end());
    
    int myarray[] = { 501, 502, 503 };
    myvector.insert(myvector.begin(), myarray, myarray + 3);
    
    std::cout << "myvector contains:"
    for (it = myvector.begin(); it < myvector.end(); it++)
        std::cout << ' ' << *it;
    std::cout << '\n';
    
    return 0;
}
Output:
myvector contains: 501 502 503 300 300 400 400 200 100 100 100

std::vector::erase     Erase elements

Removes from the vector either a single element (position) or a range of elements ([first,last)).

// erasing from vector
#include <iostream>
#include <vector>

int main ()
{
    std::vector<int> myvector;

    // set some values (from 1 to 10)
    for (int i = 1; i <= 10; i++) 
        myvector.push_back(i);

    // erase the 6th element
    myvector.erase(myvector.begin() + 5);

    // erase the first 3 elements:
    myvector.erase(myvector.begin(), myvector.begin) + 3);

    std::cout << "myvector contains:";
    for (unsigned i = 0; i < myvector.size(); ++i)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';

    return 0;
}
Output:
myvector contains: 4 5 7 8 9 10

std::vector::swap     Swap content

swap vector

// swap vectors
#include <iostream>
#include <vector>

int main ()
{
    std::vector<int> foo (3,100);   // three ints with a value of 100
    std::vector<int> bar (5,200);   // five ints with a value of 200

    foo.swap(bar);

    std::cout << "foo contains:";
    for (unsigned i=0; i<foo.size(); i++)
        std::cout << ' ' << foo[i];
    std::cout << '\n';

    std::cout << "bar contains:";
    for (unsigned i=0; i<bar.size(); i++)
        std::cout << ' ' << bar[i];
    std::cout << '\n';

    return 0;
}
Output:
foo contains: 200 200 200 200 200 
bar contains: 100 100 100 

std::vector::clear      Clear content

clearing vectors

// clearing vectors
#include <iostream>
#include <vector>

int main ()
{
    std::vector<int> myvector;
    myvector.push_back (100);
    myvector.push_back (200);
    myvector.push_back (300);

    std::cout << "myvector contains:";
    for (unsigned i=0; i<myvector.size(); i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';

    myvector.clear();
    myvector.push_back (1101);
    myvector.push_back (2202);

    std::cout << "myvector contains:";
    for (unsigned i=0; i<myvector.size(); i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';

    return 0;
}
Output:
myvector contains: 100 200 300
myvector contains: 1101 2202

std::vector::emplace    Construct and insert element

构建并添加元素

返回值指向新放置元素的迭代器。

通过在位置插入一个新元素来扩展容器。这个新元素是使用args作为构造的参数来构建的。

这有效地将容器尺寸增加了一个。

分配的存储空间的自动重新分配发生,当且仅当新的向量大小超过当前的向量容量。

由于向量使用数组作为其底层存储,因此将元素插入到向量端以外的位置会导致容器将所有位置之后的元素移位到新的位置。与其他类型的序列容器(例如list或forward_list)执行的操作相比,这通常是一个低效的操作。对于直接在最后扩展容器的成员函数,请参阅emplace_back。

如果重新分配发生,则与此容器相关的所有迭代器,指针和引用都将失效。

// vector::emplace
#include <iostream>
#include <vector>

int main ()
{
    std::vector<int> myvector = {10,20,30};

    auto it = myvector.emplace( myvector.begin() + 1, 100 );
    myvector.emplace( it, 200 );
    myvector.emplace( myvector.end(), 300 );

    std::cout << "myvector contains:";
    for (auto& x: myvector)
        std::cout << ' ' << x;
    std::cout << '\n';

    return 0;
}
Output:
myvector contains: 10 200 100 20 30 300

std::vector::emplace_back Construct and insert element at the end 

在向量的末尾插入一个新的元素,就在其最后一个元素之后。这个新元素是使用args作为构造函数的参数构建的。

这有效地将容器大小增加1,这导致所分配的存储空间的自动重新分配,当仅当新的向量大小超过当前向量容量时。  

// vector::emplace_back
#include <iostream>
#include <vector>

int main ()
{
    std::vector<int> myvector = {10,20,30};

    myvector.emplace_back (100);
    myvector.emplace_back (200);

    std::cout << "myvector contains:";
    for (auto& x: myvector)
        std::cout << ' ' << x;
    std::cout << '\n';

    return 0;
}
Output:
myvector contains: 10 20 30 100 200