C++轮子 · STL 序列容器

这篇具有很好参考价值的文章主要介绍了C++轮子 · STL 序列容器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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,大部分人的第一反应是容器,而提到容器大部分人首先想到的是std::vector。斯特劳斯特卢普的观点来说,std::vector是所有的容器中的首先,如果你不清楚应该使用哪个容器,那就选std::vector吧(当然,你不应该不清楚选哪个容器,合格是程序员对自己写的代码应该要了如指掌)。

std::vector的使用非常简单,下面是一个简单的例子。

#include <vector>                               // 1

int main(int argc, char* argv[]) {
    std::vector<int> ages = { 1, 2, 3, 4 };     // 2
    return 0;
}

头文件

// 1中引入了std::vector的头文件,需要注意的是所有C++标准库的头文件都是没有.h结尾的。这么做是为了区分,C标准库的头文件和C++标准库的头文件。比如最具代表性的:

#include <string.h>     // C 标准库头文件,包含 strlen,memset 等函数
#include <string>       // C++ 标准库头文件,包含 std::string 类

此外对于所有C标准库头文件,如果你是在C++项目中引用,你应该使用#include <cxxx>这种方式而不是#include <xxx.h>这种形式。也就是说我们应该使用#include <cstring>而不是#include <string.h>

std::vector 还是 vector

我见过很多的人(包括很多书)的习惯是在源文件头部写上using namespace std;然后在代码中使用vector<int>,而不是直接使用std::vector<int>

我个人的习惯是直接使用std::vector<int>,因为namespace对我来说是一个模块,写明了std::有更强的模块内聚表达力,而且也不太容易出现名字碰撞。

初始化

// 2在构造std::vector的时候直接给了初始值,这是C++11的特性,在C++11之前不能这样写,有一种大致等同的写法如下:

int initilizer[4] = { 1, 2, 3, 4 };
std::vector<int> ages(initilizer, initilizer + 4);

std::vector<int> ages = { 1, 2, 3, 4 }这种写法实际上从语法分析上来说是分成下面几个步骤的:

  1. { 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);

当然上面的分析只是语法上的分析,绝大部分编译器都可以优化掉tmp,而且因为{1, 2, 3, 4}转换成std::initializer_list是编译器在编译器完成的事情,所以其实效率比我们想象中要高一些。

std::vector

std::vector有一个特化版本std::vector<bool>,用于实现dynamic bitset,需要注意的是,这个特化版本并不是容器,它的迭代器无法很好的适配STL中的所有算法。它的存在是为了节省空间,它的每一个元素只占用一位而不是一个字节。为了实现这种优化,operator[]返回的是一个代理类,你没有办法取单个元素的地址。通常的建议是,如果你不需要动态的bitset,你可以使用std::bitset,如果你需要dynamic bitset你可以考虑使用std::deque<bool>替代。

push_back vs emplace_back

C++11在容器尾部添加一个元素调用的函数是push_back,它在libcxx中的实现如下:

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 参数的构造,一次是容器内部原始的拷贝构造。也就是说使用拷贝构造在末尾构造一个新的元素。emplace_back是C++11为减少其中一次拷贝而引入的新的接口,在libcxx中的实现如下文章来源地址https://www.toymoban.com/news/detail-798513.html

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_),
            

到了这里,关于C++轮子 · STL 序列容器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ STL set容器

    和 map、multimap 容器不同,使用 set 容器存储的各个键值对,要求键 key 和值 value 必须相等。 举个例子,如下有 2 组键值对数据: {\\\'a\\\', 1, \\\'b\\\', 2, \\\'c\\\', 3} {\\\'a\\\', \\\'a\\\', \\\'b\\\', \\\'b\\\', \\\'c\\\', \\\'c\\\'} 显然,第一组数据中各键值对的键和值不相等,而第二组中各键值对的键和值对应相等。对于 set 容器来

    2024年02月02日
    浏览(41)
  • C++提高编程——STL:string容器、vector容器

    本专栏记录C++学习过程包括C++基础以及数据结构和算法,其中第一部分计划时间一个月,主要跟着黑马视频教程,学习路线如下, 不定时更新,欢迎关注 。 当前章节处于: ---------第1阶段-C++基础入门 ---------第2阶段实战-通讯录管理系统, ---------第3阶段-C++核心编程, -----

    2024年01月23日
    浏览(49)
  • C++ [STL容器反向迭代器]

    本文已收录至《C++语言》专栏! 作者:ARMCSKGT 我们知道STL大部分容器都有迭代器,迭代器又分为正向迭代器和反向迭代器,对于正向迭代器以及实现前面我们已经了解了不少,而反向迭代器的设计思想是 适配器模式 ,本节我们介绍反向迭代器的实现! 适配器是把一个类的接

    2024年02月11日
    浏览(58)
  • C++ [STL容器适配器]

    本文已收录至《C++语言》专栏! 作者:ARMCSKGT 前面我们介绍了适配器模式中的反向迭代器,反向迭代器通过容器所支持的正向迭代器适配为具有反向迭代功能的迭代器,本节我们介绍STL中另一种适配器: 容器适配器 ! 前面我们提到过STL适配器模式,关于适配器的解释: S

    2024年02月11日
    浏览(44)
  • C++标准库STL容器详解

    容器都是类模板,它们实例化后就成为容器类。用容器类定义的对象称为容器对象。对象或变量插入容器时,实际插入的是对象或变量的一个复制品。 顺序容器 1、元素在容器中的位置同元素的值无关,即容器不是排序的。 2、顺序容器包括:vector、deque、list。 关联容器 1、

    2024年02月10日
    浏览(32)
  • 【C++学习】STL容器——list

    目录 一、list的介绍及使用 1.1 list的介绍  1.2 list的使用 1.2.1 list的构造  1.2.2  list iterator的使用 1.2.3 list capacity 1.2.4 list element access 1.2.5 list modifiers 1.2.6 list 迭代器失效 二、list的模拟实现 2.1 模拟实现list 三、list和vector的对比 一、list的介绍及使用 1.1 list的介绍 list的文档介绍

    2024年02月14日
    浏览(39)
  • C++ —— STL容器【vector】模拟实现

    本章代码gitee仓库:vector模拟实现、vector源码 看源码发现 vector 是类模板定义的,成员是采用迭代器进行管理 当涉及到容器类时,通常有一些关键函数,如构造函数、析构函数和拷贝构造函数,它们负责初始化容器对象、销毁对象和进行对象的拷贝等 这里注意拷贝构造要实现

    2024年02月16日
    浏览(46)
  • C++ ——STL容器【list】模拟实现

    代码仓库: list模拟实现 list源码 数据结构——双向链表 源码的list是双向带头循环链表,所以我们定义两个节点,一个指向下一个,一个指向前一个 list类包含一个 _head 头节点,然后为了方便查出当前有多少个节点,还能多定义一个 _size 源码的迭代器设置了三个模板参数:

    2024年02月15日
    浏览(45)
  • C++ STL无序关联式容器(详解)

    继 map、multimap、set、multiset 关联式容器之后,从本节开始,再讲解一类“特殊”的关联式容器,它们常被称为“无序容器”、“哈希容器”或者“无序关联容器”。 注意,无序容器是 C++ 11 标准才正式引入到 STL 标准库中的,这意味着如果要使用该类容器,则必须选择支持

    2024年02月12日
    浏览(36)
  • C++ STL set容器使用教程

    set 为关联式容器,翻译为 集合 ,其中的元素类型为 pair ,需要注意 set 容器存储的各个键值对,要求键 key 和值 value 必须相等 基于 set 容器的这种特性,当使用 set 容器存储键值对时,只需要为其提供各键值对中的 value 值(也就是 key 的值)即可。 set 容器 会自行根据键的大

    2024年02月10日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包