STL中大家最耳熟能详的可能就是容器,容器大致可以分为两类,序列型容器(SequenceContainer)和关联型容器(AssociativeContainer)这篇文章中将会重点介绍STL中的各种序列型容器和相关的容器适配器。主要内容包括
- std::vector
- std::array
- std::deque
- std::queue
- std::stack
- std::priority_queue
- std::list
- std::forward_list
std::vector
提到STL,大部分人的第一反应是容器,而提到容器大部分人首先想到的是
#include <vector> // 1 int main(int argc, char* argv[]) { std::vector<int> ages = { 1, 2, 3, 4 }; // 2 return 0; }
头文件
#include <string.h> // C 标准库头文件,包含 strlen,memset 等函数 #include <string> // C++ 标准库头文件,包含 std::string 类
此外对于所有C标准库头文件,如果你是在C++项目中引用,你应该使用
std::vector 还是 vector
我见过很多的人(包括很多书)的习惯是在源文件头部写上
我个人的习惯是直接使用
初始化
int initilizer[4] = { 1, 2, 3, 4 }; std::vector<int> ages(initilizer, initilizer + 4);
{ 1, 2, 3, 4 } 被编译器构造成一个临时变量std::initializer_list<int> ,然后使用临时变量构造一个临时变量std::vector<int> ,然后再用std::vector<int> 的拷贝构造函数构造最终的ages
std::initializer_list<int> initilizer; std::vector<int> tmp(initilizer); std::vector<int> ags(tmp);
当然上面的分析只是语法上的分析,绝大部分编译器都可以优化掉
std::vector
push_back vs emplace_back
C++11在容器尾部添加一个元素调用的函数是
template <class _Tp, class _Allocator> inline _LIBCPP_INLINE_VISIBILITY void vector<_Tp, _Allocator>::push_back(const_reference __x) { if (this->__end_ != this->__end_cap()) { __RAII_IncreaseAnnotator __annotator(*this); __alloc_traits::construct(this->__alloc(), _VSTD::__to_raw_pointer(this->__end_), __x); __annotator.__done(); ++this->__end_; } else __push_back_slow_path(__x); }
这里存在两次元素的构造,一次是 __x 参数的构造,一次是容器内部原始的拷贝构造。也就是说使用拷贝构造在末尾构造一个新的元素。
template <class _Tp, class _Allocator> template <class... _Args> inline #if _LIBCPP_STD_VER > 14 typename vector<_Tp, _Allocator>::reference #else void #endif vector<_Tp, _Allocator>::emplace_back(_Args&&... __args) { if (this->__end_ < this->__end_cap()) { __RAII_IncreaseAnnotator __annotator(*this); __alloc_traits::construct(this->__alloc(), _VSTD::__to_raw_pointer(this->__end_),