C++源码剖析——forward_list

  前言:之前看过侯老师的《STL源码剖析》但是那已经是多年以前的,现在工作中有时候查问题和崩溃都需要了解实际工作中使用到的STL的实现。因此计划把STL的源码再过一遍。
  摘要:本文描述了llvm中libcxx的forward_list的实现。
  关键字forward_list
  其他:参考代码LLVM-libcxx
  注意:参考代码时llvm的实现,与gnu和msvc的实现都有区别。

  forward_list是STL中的单向链表序列容器,可以在任意位置快速插入(前提是直到期望插入的位置),不支持快速的随机访问。需要注意的是因为forward_list是单向链表也就意味着size相关的函数可能是O(1)的。
  forward_list的定义如下:

template <class _Tp, class _Alloc /*= allocator<_Tp>*/>
class _LIBCPP_TEMPLATE_VIS forward_list : private __forward_list_base<_Tp, _Alloc>{

};

1 __forward_list_base

在这里插入图片描述

  forward_list是基于__forward_list_base实现的,其中只有一个头结点。

template <class _Tp, class _Alloc>
class __forward_list_base{
protected:
    __compressed_pair<__begin_node, __node_allocator> __before_begin_;
};

1.1 节点

  链表中由两种节点,一种是__begin_node是链表的头结点,另一种是__node是链表内数据成员的节点,其存储链表中保存的数据。

    typedef __forward_list_node<value_type, void_pointer>            __node;
    typedef __begin_node_of<value_type, void_pointer>                __begin_node;

  二者的区别就是将索引和值域区分了开来。从下面的代码可以看出__begin_node就是一个指针的adapter,而__forward_list_node和我们常见的链表节点没什么区别。这样做的好处是在使用迭代器时只需要一个指针的空间就可以表示索引,而不用每个迭代器都携带一个没用的value域,浪费空间。

template <class _NodePtr>
struct __forward_begin_node{
    typedef _NodePtr pointer;
    typedef __rebind_pointer_t<_NodePtr, __forward_begin_node> __begin_node_pointer;
    pointer __next_;
    _LIBCPP_INLINE_VISIBILITY __forward_begin_node() : __next_(nullptr) {}
    __begin_node_pointer __next_as_begin() const {
        return static_cast<__begin_node_pointer>(__next_);
    }
};

template <class _Tp, class _VoidPtr>
using __begin_node_of = __forward_begin_node<__rebind_pointer_t<_VoidPtr, __forward_list_node<_Tp, _VoidPtr> > >;

template <class _Tp, class _VoidPtr>
struct _LIBCPP_STANDALONE_DEBUG __forward_list_node : public __begin_node_of<_Tp, _VoidPtr>{
    typedef _Tp value_type;
    value_type __value_;
};

1.2 __forward_list_base

  __forward_list_base就是存储了一个节点__before_begin_,简单封装了一些拷贝和move的函数,唯一有点儿代码的就是clear(),代码也比较简单就是用for-loop析构对象释放节点的内存。

template <class _Tp, class _Alloc>
void __forward_list_base<_Tp, _Alloc>::clear() _NOEXCEPT{
    __node_allocator& __a = __alloc();
    for (__node_pointer __p = __before_begin()->__next_; __p != nullptr;){
        __node_pointer __next = __p->__next_;
        __node_traits::destroy(__a, _VSTD::addressof(__p->__value_));
        __node_traits::deallocate(__a, __p, 1);
        __p = __next;
    }
    __before_begin()->__next_ = nullptr;
}

2 forward_list

2.1 迭代器

  在了解具体实现前明白迭代器是如何实现的可以帮助我们理解内存布局方式。forward_list迭代器的实现比较简单就是一个__forward_list_node的指针。

template <class _NodePtr>
class _LIBCPP_TEMPLATE_VIS __forward_list_iterator{
    //__forward_list_node *
    __iter_node_pointer __ptr_;
};

  因为是单项链表因此只支持一种方向的索引,实现也比较简单就是当前节点的next指针。

__forward_list_iterator& operator++(){
        __ptr_ = __traits::__as_iter_node(__ptr_->__next_);
        return *this;
    }

2.2 forward_list

  forward_list是继承自__forward_list_base

template <class _Tp, class _Alloc /*= allocator<_Tp>*/>
class _LIBCPP_TEMPLATE_VIS forward_list : private __forward_list_base<_Tp, _Alloc>{};

  因为是单向链表因此只允许头插,实现也比较简单就是创建节点,然后将对应的指针指向对应的节点。

template <class _Tp, class _Alloc>
void forward_list<_Tp, _Alloc>::push_front(value_type&& __v){
    __node_allocator& __a = base::__alloc();
    typedef __allocator_destructor<__node_allocator> _Dp;
    unique_ptr<__node, _Dp> __h(__node_traits::allocate(__a, 1), _Dp(__a, 1));
    __node_traits::construct(__a, _VSTD::addressof(__h->__value_), _VSTD::move(__v));
    __h->__next_ = base::__before_begin()->__next_;
    base::__before_begin()->__next_ = __h.release();
}

template <class _Tp, class _Alloc>
void forward_list<_Tp, _Alloc>::pop_front()
{
    __node_allocator& __a = base::__alloc();
    __node_pointer __p = base::__before_begin()->__next_;
    base::__before_begin()->__next_ = __p->__next_;
    __node_traits::destroy(__a, _VSTD::addressof(__p->__value_));
    __node_traits::deallocate(__a, __p, 1);
}

template <class _Tp, class _Alloc>
typename forward_list<_Tp, _Alloc>::iterator
forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, const value_type& __v){
    __begin_node_pointer const __r = __p.__get_begin();
    __node_allocator& __a = base::__alloc();
    typedef __allocator_destructor<__node_allocator> _Dp;
    unique_ptr<__node, _Dp> __h(__node_traits::allocate(__a, 1), _Dp(__a, 1));
    __node_traits::construct(__a, _VSTD::addressof(__h->__value_), __v);
    __h->__next_ = __r->__next_;
    __r->__next_ = __h.release();
    return iterator(__r->__next_);
}

  其他几个函数的实现都是改变节点之类的比较简单就不详细描述了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/6597.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【排序算法】排序算法介绍及插入排序 ( 直接插入排序 希尔排序 )

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录1.排序的概念和运用1…

关于Warning: World-writable config file ‘/etc/mysql/my.cnf‘ is ignored

不知道那个大兄弟&#xff0c;更改了my.cnf的权限为 0777 登陆mysqll的时候提示&#xff1a;Warning: World-writable config file /etc/mysql/my.cnf is ignored 里面的配置被忽略了, my.cnf不起作用 如果不是安装在docker里面的话&#xff0c;直接 chmod 0644 /etc/mysql/…

Java每日一练(20230405)

目录 1. 地下城游戏 &#x1f31f;&#x1f31f;&#x1f31f; 2. 汇总区间 &#x1f31f;&#x1f31f; 3. 寻找旋转排序数组中的最小值 II &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C…

Selenium被检测为爬虫,怎么屏蔽和绕过

01、Selenium 操作被屏蔽 使用selenium自动化网页时&#xff0c;有一定的概率会被目标网站识别&#xff0c;一旦被检测到&#xff0c;目标网站会拦截该客户端做出的网页操作。 比如淘宝和大众点评的登录页&#xff0c;当手工打开浏览器&#xff0c;输入用户名和密码时&#x…

Java SE 基础 (6) 第一个Java程序

开发环境已经搭建完毕&#xff0c;可以开发我们第一个Java程序了。 Java程序开发三步骤&#xff1a;编写、编译、运行。 编写Java源程序 public class HelloWord {public static void main(String[] args) {System.out.println("HelloWord!");} } 第一个 HelloWo…

蓝桥杯 路径

答案 import mathdef lcm(i,j):m math.gcd(i,j)return i*j//m n 2021 dp [float(inf)]*2022 dp[1] 0 for i in range(1,n1):for j in range(i1,i22):if j > n:breakdp[j] min(dp[j],dp[i]lcm(i,j)) print(dp[n]) 对dp[j] min(dp[j],dp[i]lcm(i,j))的解析&#xff1a;…

JAVASE 继承

文章目录继承1.为什么需要继承2.继承的概念3.继承的语法4.父类成员访问4.1 子类中访问父类的成员变量4.2 子类中访问父类的成员方法5 super关键字6.子类的构造方法7.super和this8.再谈初始化9.protected关键字10.继承方法11.final 关键字12.继承与组合继承 1.为什么需要继承 …

【C++笔试强训】第十天

选择题 解析&#xff1a;内联函数&#xff08;inline&#xff09;一般用于代码较少&#xff0c;代码块里面没有递归且频繁调用的函数&#xff0c;是一种以空间换时间&#xff08;不是指内存&#xff0c;而是指令变多编译出来的可执行程序会变大&#xff09;的做法。内联函数在预…

49天精通Java,第14天,Java泛型方法的定义和使用

目录一、基本介绍1、Java泛型的基本语法格式为&#xff1a;2、在使用泛型时&#xff0c;还需要注意以下几点&#xff1a;二、泛型的优点1、类型安全2、消除强制类型转换3、更高的效率4、潜在的性能收益三、常见泛型字母含义四、使用泛型时的注意事项五、泛型的使用1、泛型类2、…

第五章 Vite4+Vue3+Vtkjs 自定义按键组合

一、介绍 因为Vtk.js在按键和按键组合上默认就指定了对应的事件处理,但是我们在使用其他软件的时候可能已经养成了一种习惯,然后也希望使用Vtk.js的时候按键对应的事件也是一致的。比如右键是平移模型,或者说shift+鼠标右键是平移,不管是什么按键的组合,对应的事件是我们…

颠覆认知!“垃圾股”策略长期跑,10年翻100倍、近2年6倍,吊打茅指数!| 邢不行

这是一个非常简单的量化选股策略&#xff0c;它只用到了两个基础选股指标。 代表策略的橙色曲线2010年至今从1元涨到了112元&#xff0c;年化收益43%&#xff1b;在近两年大盘下跌的情况下&#xff0c;这个策略更是逆势翻了6倍。 这个量化策略究竟用了哪两个选股指标&#xf…

java TreeSet 和 TreeMap 源码解读

目录 一、前言 二、TreeSet详解 1.TreeSet简介 2.TreeSet的底层实现 0 准备工作 1 TreeSet构造器 2 匿名内部类实现接口的多态 3 TreeMap构造器 4 add方法 5 put方法和put方法 6 继续添加元素 7 修改比较器的比较原则 三、TreeMap详解 1.TreeMap简介 2.TreeMap的底层实现 0…

拥有良好的社交和友谊会使肠道微生物群更健康

谷禾健康 播种肠道&#xff0c;喂养心灵 在新冠疫情的影响下&#xff0c;我们的生活方式和社交模式都发生了很大的改变。随着社交距离的要求和封锁措施的实施&#xff0c;我们不得不放弃了很多与朋友和家人的互动&#xff0c;这给我们的身心健康带来了很大的影响。 然而&#x…

区块链学习笔记(3)BTC协议

假设有一个大家都信任的中心化机构想要发行数字货币。 该机构由用自己的私钥签名后后发行&#xff0c;任何人都可以通过公钥验证该货币是否为真。 买东西的时候&#xff0c;购买者可以将数字货币发送给卖方&#xff0c;卖方可以也可以通过公钥验证该货币为真后即可完成支付的过…

子网掩码和CIDR

CIDR是什么 网络标识相同的计算机必须同属于同一个链路。例如&#xff0c;架构B类IP网络时&#xff0c;理论上一个链路内允许6万5千多台计算机连接。然而&#xff0c;在实际网络架构当中&#xff0c;一般不会有在同一个链路上连接6万5千多台计算机的情况。因此&#xff0c;这种…

蓝桥杯刷题冲刺 | 倒计时7天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;最后一周&#xff0c;复习学过的知识&#xff0c;刷题冲刺&#x1f43e; 文章目录1.高精度除法2.扫地机器人3.数的范围4.A-B 数对1.高精度除法 题目 链接&#xff1a; 794. 高精度除法 - AcWing题…

Java对象内存布局

文章目录1、对象头对象标记Mark Word类元信息&#xff08;又叫类对象指针&#xff09;Class Pointer数组长度&#xff08;Array Length&#xff09;&#xff08;可选&#xff09;2、实例数据&#xff08;对象体&#xff09;3、对齐填充4、指针压缩5、再聊对象头的MarkWord6、JO…

Android ART虚拟机 Space类体系

前言 在ART虚拟机实现中&#xff0c;内存分配和释放的算法是封装在不同的Space中来完成的。而外部使用者只能借助Space及派生类的接口来完成内存的分配与释放。通过阅读这些Space的实现&#xff0c;可以看出ART虚拟机的一个重要的特点就是大量使用映射内存&#xff0c;相较于D…

思维导图软件哪个好?安利八款好用的思维导图软件

当你需要表达和整理复杂的想法、计划和项目时&#xff0c;思维导图软件可以是非常有用的工具。不同的思维导图软件有不同的功能和特点&#xff0c;选择适合自己的软件可以让你更高效地工作和学习。但是你了解思维导图软件哪个好呢&#xff1f;下面就给大家安利八款简单好用的思…

分享99个ASP影音娱乐源码,总有一款适合您

分享99个ASP影音娱乐源码&#xff0c;总有一款适合您 99个ASP影音娱乐源码下载链接&#xff1a;https://pan.baidu.com/s/1pYpAqFUX0xD8KR8GDRyiug?pwd3lja 提取码&#xff1a;3lja Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 我的博客地址&#xff1a;亚…