C++ 顺序容器基础知识总结

本文简单地总结了STL的顺序容器的知识点。文中并不涉及具体的实现技巧,对于细节的东西也没有提及。一来不同的标准库有着不同的实现,二来关于具体实现《STL源码剖析》已经展示得全面细致。所以本文仅仅是对容器基础知识的归纳。至于容器提供的接口与使用实例,建议查取官方文档。文章难免有错漏,希望指出。

容器概论

容器,置物之所也。像桶可装水,碗可盛汤,C++的容器,可以存储对象。容器有多种,用来处理不同的元素操作诉求。按照元素存储到容器中以及访问方式的差异,容器分为顺序容器与关联容器。顺序容器也称为序列式容器。序列式容器按元素插入的顺序存储元素,这些元素可以进行排序,但未必是有序的。C++本身内置了一个序列式容器array(数组),STL另外提供了vector,list,forward_list,deque,stack,queue,priority-queue,string等等序列式容器。所有的容器都是基于模板实现的,因为容器必须保证能装得下各种各样的类型。其中,stack,queue都是基于deque来实现的,priority-queue基于heap来实现,从技术上来说它们属于容器适配器(adapter)。其中array与forward_list是C++11添加的新容器类型。

std::array 底层数据结构

array的底层数据结构是固定数组。与C-style的数组类似,它的大小在定义后就不能被改变。由于array具有固定的大小,它不支持添加和删除元素或改变容器大小等其他容器拥有的操作。在定义一个array容器的时候必须指定大小:

Defined in header <array> template< class T, std::size_t N > struct array;

内存分配策略

在内存分配策略上,array也与C-style数组类似。编译器在哪里为array分配内存,取决于array定义的位置和方式。

若作为函数的局部对象,则将从栈上获得内存,与之对比是的vector,vector底层数据结构是动态数组,从自由存储区上分配内存:

若使用new操作符分配内存,则是在自由存储区上分配内存。

若作为全局变量或局部静态变量,则是在全局/静态存储区上分配的内存。

例如,在函数定义的array局部对象在栈上分配内存,与此对比的是vector,它底层数据结构为动态数组,因此在自由存储区上分配内存:

#include <array> #include <vector> #include <iostream> using namespace std; int main() { int stack_var; array<int, 5> a; vector<int> b(5); cout << "stack area: 0x" << hex << (uintptr_t)&stack_var << endl; cout << "a[3] address: 0x" << hex << (uintptr_t)&a[3] << endl; cout << "b[3] address: 0x" << hex << (uintptr_t)&b[3] << endl; getchar(); return 0; }

结果:

C++ 顺序容器基础知识总结

array的优势在哪

array比数组更安全。它提供了opeartor[]与at()成员函数,后者将进行数组越界检查。

与其他容器相似,array也有自己的迭代器,因此array能够更好地与标准算法库结合起来。

通过array::swap函数,可以实现线性时间内的两个数组内容的交换。

另外,不像C-style数组,array容器类型的名称不会自动转换为指针。对于C++程序员来说,array要比C-style数组更好用。

forward_list 底层数据结构

forward_list的底层数据结构为单向链表。如C++标准所讲,forward_list容器支持前向遍历元素序列,允许常数时间内在任意位置的插入或删除操作并进行自动的内存管理。与list的主要区别是forward_list没有反方向的迭代器,不过也正因如此,forward_list的每个节点都节省了迭代器大小的开销,在元素众多的时候,将比list消耗少得多的内存。

受单向链表这种特殊结构的影响,forward_list在很多地方表现得和其他容器不同:

不同之一:forward_list不提供返回其大小的操作。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/e02ebb27068036e01c0191964180e206.html