C++基础知识 - vector

概述

vector,直译为向量,我们一般称为动态数组,一般不去翻译,直接使用vector称呼。它是STL诸多数据结构中使用最广泛的几个数据结构之一。C++编程规范中指出,如果你不知道使用哪个容器合适,就使用vector吧。无论从使用的方便程度和效率上,都可圈可点。下面详细学习该数据结构,以C++11为准。

创建

构造函数:

类别 声明
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
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 il, const allocator_type& alloc = allocator_type());

默认构造

std::vector<T> vec; // 创建一个元素类型为T的空数组

填充构造

std::vector<T> vec(1);    // 创建一个元素类型为T的数组,数组大小为1,元素内容为0
std::vecotr<T> vec(1, 2); // 创建一个元素类型为T的数组,数组大小为1,元素内容为2

查看

empty
bool empty() const noexcept;

查看vector是否为空,size 为 0,则为true。建议使用该函数来查看vector是否为,而不是比较size() == 0.

大小
size_type size() const noexcept;
size_type capacity() const noexcept;

size和capacity的关系如下:

+---+---+---+---+---+----------+
| 0 | 1 | 2 |...| 23| reserved |
+---+---+---+---+---+----------+
                    |          |
                  size()   capacity()

size是指vector已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。

访问元素
reference front();
const_reference front() const;

reference back();
const_reference back() const;

reference operator[] (size_type n);
const_reference operator[] (size_type n) const;

reference at (size_type n);
const_reference at (size_type n) const;

访问元素的方式,可以通过front(),back(),下标和at()几种成员函数。它们返回的均是引用,如果vector是一个const对象,则返回值是const的引用。对于非const引用,我们可以通过该返回值,来修改容器中该元素的值。

增加

push_back
void push_back (const value_type& val);
void push_back (value_type&& val);

通过成员函数push_back往vector的末尾添加元素,这个效率是非常高的。

// 往vector末尾依次添加两个元素
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
emplace_back
template <class... Args>
void emplace_back (Args&&... args);

在C++11增加了新的成员函数,用于在vector末尾插入数据。

// 往vector末尾依次添加两个元素
std::vector<int> vec;
vec.emplace_back(1);
vec.emplace_back(2);

和push_back的区别在于,如果vector的元素是一个对象时,push_back接受的是一个对象,而emplace_back接受的是构造这个对象的参数。

class A {
public:
	A(int arg){}
    ... ...
}
// 使用push_back存储
std::vector<A> vec;
A a(1);
vec.push_back(a);
// 使用emplace_back存储
std::vector<A> vec;
vec.emplace_back(1);
总结
  • 其他类似功能成员函数

    vector除了上面介绍的两种添加元素的成员函数,还有insert,push_front, emplace等。但,插入vector末尾是最高效的,上面的两种函数使用最广泛。不要贪多,容易混乱。

  • 拷贝

    需要注意的是,往vector中添加元素时,添加的是拷贝,不是本尊。如上面的例子中的a对象,存储到vector时,存储的是a对象的拷贝,不是a自身。

  • 指针

    在vector中存储指针时需要注意,vector管理的是指针自身,并不负责指针指向的内容。在销毁vector或删除元素时,需要自己提前处理该指针对应的内存。比较好的解决方案是使用智能指针。

删除

pop_back
void pop_back();

前面介绍的push_back用于在vector的末尾添加元素,与之对应的pop_back则是从vector的末尾删除元素。

std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
// 从末尾删除一个元素
vec.pop_back();
// 此时vec中只有1这一个元素了
erase
iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);

删除迭代器指定的元素,获取迭代器指定范围内的元素。返回一个指向被删除元素之后元素的迭代器。

std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
// 删除vector中元素为奇数的元素
std::vector<int>::iterator it = vec.begin();
while (it != vec.end()) {
    if (*it % 2) {
        it = vec.erase(it);
    } else {
        ++it;
    }
}
// 此时vec中只有2这一个元素了

注意:

  • erase返回的是指向被删除元素之后的那个元素,所以,删除之后,获取该迭代器指针,不需要自增了。务必每次erase之后获取该返回值。
  • 由于删除元素,导致尾部迭代器指针可能发生变化,所以,每次循环必须重新获取尾部迭代器指针。不可以循环之前保存它的副本,循环时和副本比较,不要这样操作。
clear
void clear() noexcept;

删除vector的所有元素,即清空vector。vector的size为0,但是,capacity并不没有变化,即之前的为所有元素申请的内存并未释放。

释放的经典方式为:

std::vector<T>().swap(x);     // clear x reallocating
// 举例
std::vector<int> vec(4, 1);   // 创建一个拥有4个元素的vector,此时vector的size: 4, capacity: 4
vec.clear();                  // 此时vector的size: 0, capacity: 4
std::vector<int>().swap(vec); // 此时vector的size: 0, capacity: 0,之前存储元素所有的内存成功释放

原理是:

  • 创建一个相同类型的临时变量,std::vector()

  • 临时变量和带操作变量即vec交换

    交换后,临时变量管理vec的内存,vec管理临时变量的内存,临时变量是空的vector,所以,交换后的vec也就是空vector了

  • 临时变量销毁

    因为是临时变量,在当前行代码执行完后,临时变量就销毁。随着销毁的还有它管理的之前vec的内存。

通过上面的三步,vec的多余内存得以释放。C++11增加了成员函数shrink_to_fit,用于解决退还内存的问题。但是,调用shrink_to_fit只是一个请求,标准库并不保证退还内存。

修改

reserve
void reserve (size_type n);

reserve用来通知容器应该准备保存多少个元素。它改变的是capacity的大小。只有当需要的内存空间超过当前容量时,reserve调用才会改变vector的容量。

如果事先知道自己大约需要保存多少个元素,可以调用该成员函数,事先申请内存,这样不至于随着元素的增加,标准库内部反复重新申请和释放内存。

resize
void resize (size_type n);
void resize (size_type n, const value_type& val);

resize用来增大或缩写容器,它改变的是size的大小。如果当前大小大于所要求的大小,则容器后部的元素会被删除;如果当前大小小于新大小,会将新元素添加到容器后部;

std::vector<int> vec(3, 1); // 创建一个vector,包含3个元素,初始化值均为1,内容为:1 1 1
vec.resize(4); 				// 调整vector元素为4个,最新增加的一个元素为0,内容为:1 1 1 0
vec.resize(8, 2); 			// 调整vector元素为8个,最新增加的4个元素为2,内容为:1 1 1 0 2 2 2 2
vec.resize(6);				// 调整vector元素为8个,删除后面多余的两个元素,内容为:1 1 1 0 2 2

参考

  • http://www.cplusplus.com/reference/vector/vector/

  • C++ primer 第五版

你可能感兴趣的:(C/C++,c++)