0%

RCU (读-复制-更新)

RCU(Read-Copy-Update,读-拷贝-更新)是 Linux 内核中一种高效的 并发读-写同步机制,专门用于在多核系统下实现 大量读、少量写 的场景。它的核心思想是:读操作完全无锁,写操作通过复制更新,最后再安全地回收旧版本。

RCU 的核心思想

  • 读操作直接访问数据结构,不加锁
  • 写操作:
    • 先 复制原数据 → 修改副本
    • 更新指针,使新数据生效
    • 延迟回收旧数据,保证当前正在读取旧数据的线程不受影响

__rcu

它是 RCU 机制中非常关键的一环,用来让 编译器和内核知道某个指针是 RCU 保护的。

  1. __rcu 的定义

在 Linux 内核中(以 x86_64 为例):

1
#define __rcu

实际上,它 本身对编译器不产生直接影响

主要用途是 标记类型,告诉 Sparse 静态分析工具 或 内核开发者:这个指针受 RCU 保护,不能随意直接读/写

也就是说,__rcu 是 一个注释性质的宏,编译器编译时忽略,但静态分析工具会检查 RCU 访问规则。

  1. __rcu 的作用

标记 RCU 保护的指针,常见用法:

1
2
3
4
struct files_struct {
struct fdtable __rcu *fdt;
struct file __rcu *fd_array[NR_OPEN_DEFAULT];
};

含义:

  • fdt 是 RCU 指针
  • 不能直接写 fdt = new_ptr; 或直接解引用 fdt->xxx
  • 必须通过 RCU API,如:
    • rcu_assign_pointer(fdt, new_fdt); → 安全更新指针
    • rcu_dereference(fdt) → 安全读取指针
  • 这样可以保证:
    • 写线程更新指针时不会破坏读线程的访问
    • 读线程可以无锁访问旧数据
  1. __rcu 与编译器和内核
  • 静态检查(Sparse)
    • Sparse 是 Linux 内核推荐的静态分析工具
    • 它会检查:
      • 所有 __rcu 指针的写操作是否用 rcu_assign_pointer
      • 所有读取是否用 rcu_dereference
    • 如果直接访问,就会报错,避免 RCU 访问错误
  • 内存屏障和优化
    • rcu_assign_pointer 内部会加上 适当的写屏障 (smp_wmb())
    • rcu_dereference 内部会加 读取屏障 (smp_rmb())
    • 防止编译器/CPU 重排导致读写顺序错误
  1. __rcu 的核心原理总结
方面 说明
编译器作用 本身是空宏,不改变代码
静态分析 Sparse 检查 RCU 指针的安全读写
内存屏障 通过 rcu_assign_pointer / rcu_dereference 添加屏障,保证并发安全
运行时 指针仍然是普通指针,实际存储和访问和普通指针一样

高效的 IO 函数

  • sendfile
  • mmap + write
  • splice
  • readv

零拷贝 (Zero copy)

  • mmap + write
  • sendfile
  • splice

Page cache 和异步 IO

https://www.xiaolincoding.com/os/8_network_system/zero_copy.html#%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E9%9B%B6%E6%8B%B7%E8%B4%9D

  • O_DIRECT: 绕过操作系统缓存,直接读写磁盘,可以避免缓存延迟,提高性能。可用于:
    • 数据库系统:对性能要求极高,且直接操作磁盘数据。
    • 存储设置:如 SSD、硬盘,直接与硬件设备进行高效的 I/O 操作。
    • 注意:由于绕过了缓存,所以 read 如果小于当前数据包的大小,则本次 read 后,内核会直接丢弃多余的数据。这是为了避免多余的数据在内存中驻留。

散布读写 (Scatter read/write)

  • readv
  • writev

散布读写支持一次性将数据从文件描述符读写到多个缓冲区:

  • 避免多次系统调用;
  • 直接分块读取,不需要额外用户态 memcpy 到不同的块。

IO 复用

  • select
  • poll
  • epoll
  • 非阻塞 IO

如果 select / poll / epoll 通知可读写,那么一定可读写吗?
答案是不一定。因为内核不是 实时地 检查内核缓冲区是否有空间或有数据,所以内核的通知有时间差和虚假性。
而 epoll 等函数只关注事件变化,不检查缓冲区。这样可以提高效率。
最终的结果就是鼓励用户程序尝试,但是不保证一定成功,也就是可能阻塞。所以需要非阻塞 IO 来进一步提高性能。

epoll

  • 减少数据拷贝:select / poll 只有一个函数,这会要求每次调用都必须将描述事件的数据从用户空间复制到内核空间;所以 epoll 拆分成三个函数,用户可以向内核直接注册事件数据;
  • 红黑树:epoll 事件数据是用红黑树来记录,增删查改的时间复杂度为 O(logn) ;select / poll 是线性扫描,时间复杂度 O(n) 。红黑树需要额外的空间,所以这是空间换时间的办法。

EPOLLONESHOT

阅读 manual:

Since even with edge-triggered epoll, multiple events can be generated upon receipt of multiple chunks of data, the caller has the option to specify the EPOLLONESHOT flag, to tell epoll to disable the associated file descriptor after the receipt of an event with epoll_wait(2). When the EPOLLONESHOT flag is specified, it is the caller’s responsibility to rearm the file descriptor using epoll_ctl(2) with EPOLL_CTL_MOD.

如果某个文件描述符上有多个数据块到达,那么即使是边沿触发也无法保证事件只通知一次。这可能是由于数据包过大被分片,或者是新数据到达。

  • 这在单线程程序上不会有太大影响,因为对同一个 fd 不会造成重复读写。
  • 多线程程序中,fd 准备好后,我们常常将这个 fd 交给某个线程去处理。此时如果 fd 有新的事件,会造成多线程处理同一个 fd 的情况。
    • 为了避免竞争,要么加锁;要么使用内核的 ONESHOT 机制。后者由内核保证,无锁,更高效。
  • EPOLLONSHOT 需要调用者自行 reset 这个标志。

参考

https://blog.csdn.net/salmonwilliam/article/details/112347938

进程打开文件

image

  • struct task_struct (进程控制块)
    • 每个进程有一个 task_struct结构体,内核用它来描述进程。
    • 里面有一个指针 files ,执行该进程的 files_struct
1
2
3
4
5
6
7
// https://elixir.bootlin.com/linux/v6.16/source/include/linux/sched.h

/* 进程控制块 */
struct task_struct {
struct files_struct *files; // 进程当前打开的文件
// ...
};
  • files_struct (进程的文件表)
    • 这里保存了一个指向 fd 数组 的指针。
    • fd 数组的下标就是 0, 1, 2…,每个元素指向一个 file * 结构体。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// https://elixir.bootlin.com/linux/v6.16/source/include/linux/fdtable.h

struct files_struct {
struct fdtable __rcu *fdt; // fd 表(动态管理)
struct file __rcu *fd_array[NR_OPEN_DEFAULT]; // 固定大小数组(早期 fd 数组)
// NR_OPEN_DEFAULT 通常为 1024
// 早期没有设置 FD_CLOEXEC 新特性
// 为什么 fdt 与 fd_array 同时存在?
// 1. 性能优化:大多数程序,fd 都在 0~1023,直接访问数组更快
// 2. 向后兼容:早期接口会访问fd_array
// 3. 动态扩展:如果 fd 超过 NR_OPEN_DEFAULT,内核会复制 fd_array 到 fdt->fd 来保证一致性。

// ... `struct files_struct' 还有其他成员
};

// fd 表(动态管理)
struct fdtable {
unsigned int max_fds;
struct file __rcu **fd; /* 当前打开的 fd 指针数组 */
unsigned long *close_on_exec; // fd 标志,目前只有一个
// FD_CLOEXEC 定义在 <fcntl.h> 中
// close_on_exec 指向一个位图(bitmap),每个bit代表一个fd
// 如果bit=1,表示该fd设置了FD_CLOEXEC
unsigned long *open_fds; // 标记哪些fd是打开的,也是位图
unsigned long *full_fds_bits; // 辅助位图,用于快速找到空闲fd
struct rcu_head rcu;
};
  • struct file (打开文件表项)
    • 内核为每次 open()pipe()socket() 创建一个 struct file
    • 它记录了文件状态(读写偏移、flag、引用计数等)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// https://elixir.bootlin.com/linux/v6.16/source/include/linux/fs.h

struct file {
spinlock_t f_lock;
fmode_t f_mode;
const struct file_operations *f_op;
struct address_space *f_mapping;
void *private_data; // 比如 socket
struct inode *f_inode;
unsigned int f_flags; // 文件状态标志,如 O_RDONLY, O_NONBLOCK, O_APPEND 等
unsigned int f_iocb_flags;
const struct cred *f_cred;
struct fown_struct *f_owner;
/* --- cacheline 1 boundary (64 bytes) --- */
struct path f_path;
union {
/* regular files (with FMODE_ATOMIC_POS) and directories */
struct mutex f_pos_lock;
/* pipes */
u64 f_pipe; // 管道
};
// ...
};
  • inode / pipe / socket 内核对象
    • struct file 再指向更底层的对象,比如 inode(磁盘文件)、socket 缓冲区、pipe 缓冲区。

    • i-node 包含以下内容

      • 链接计数(指向该i节点的目录项数);
      • 文件类型、文件访问权限位、文件长度、指向文件数据块的指针等。stat结构中的大多数信息都取自i节点。
      • 只有两项重要数据放在目录项中:文件名和i-node编号。
磁盘、分区和文件系统
磁盘、分区和文件系统
i节点和数据块
i节点和数据块

软链接与硬链接

类型 定义
硬链接 (Hard Link) 表示有多少目录项(文件名)指向同一个 inode 。它们指向同一个文件内容。
软链接 (Symbolic Link / Symlink) 类似快捷方式,是一个 独立文件,内容是指向目标文件的路径。
  • 硬链接:当硬链接数降为0时,才从磁盘的数据块中删除该文件,所以删除文件(即目录项)称为unlink,而不是delete
  • 软链接:i-node中的文件类型是S_IFLINK,表明是符号链接。
特性 硬链接 软链接
是否指向 inode 是,直接指向同一 inode 否,指向目标路径
是否可以跨文件系统 否,只能在同一分区 可以跨分区
是否可以链接目录 通常不能(除非 root) 可以
删除目标文件后 文件内容仍可访问 链接会失效(称为“悬挂链接”)
占用空间 不占用额外数据空间(只是多了一个目录项) 占用少量空间存储路径信息
更新文件内容 所有硬链接同步可见 通过软链接修改目标文件内容时可见,软链接本身只是路径

两个独立进程各自打开同一个文件

两个独立进程各自打开同一个文件

  • O_APPEND:
    • 原子操作:如果使用 O_APPEND 标志打开一个文件,那么相应的标志也被设置到文件表项的文件状态标志中。每次对文件执行写操作时,文件表项中的当前文件偏移量首先会被设置为 i 节点表项中的文件长度(相对其他进程来说是原子操作,不论是两个独立的进程,还是父子进程)。这就使得每次写入的数据都追加到文件的当前尾端处。这里有一个测试的例子,文章结论不见得正确,请参考评论的讨论。
    • PIPE_BUF:只保证小于PIPE_BUF的内容是原子;如果大于则可能被多次多段写入。PIPE_BUF 是管道(pipe)单次写入保证原子的最大字节数,Linux 上是 4096 字节。
1
2
3
4
5
6
# 查看 PIPE_BUF 大小
# `/tmp' 可以换成任意文件系统路径
$ getconf PIPE_BUF /tmp
4096
# 也可以查看所有文件系统相关的 PIPE_BUF 限制
$ getconf -a PIPE_BUF

以下是 man 2 write 关于 O_APPEND 的说明:

If the file was open(2)ed with O_APPEND, the file offset is first set to the end of the file before writing. The adjustment of the file offset and the write operation are performed as an atomic step.

  • lseek:

若一个文件用 lseek 定位到文件当前的尾端,则文件表项中的当前文件偏移量被设置为 i 节点表项中的当前文件长度(注意,此时,设置偏移量和写操作之间不是原子操作)。


dup()后的内核数据结构

dup() / dup2() 只复制 fd ,也就是在 fd 数组中新增了一个 fd 项。一般用来重定向。

dup(1)


fork与文件共享

  • 进程每打开一个文件,都会新建一个 struct file ,并添加到 fd 数组或 fd 表中。
    • 对同一个文件,不同进程拥有各自的文件表项。
    • 但是对每个文件,v节点表项在整个操作系统中只有一份。
  • fork() 后的子进程直接复制父进程的 fd 数组,exec() 也不能将其替换;
    • 子进程对 struct task_struct 是深拷贝,所以 fd 数组被复制;
    • 但是子进程对 fd 数组是浅拷贝,fd 数组中的 struct file* 仍然指向父进程创建的 struct file (共享);
    • 所以子进程共享了文件状态标志 (O_APPEND, O_NONBLOCK, O_RDONLY 等)、当前文件偏移量。
  • 除非该文件描述符使用fcntl()设置了FD_CLOEXEC标志,此时 exec 会关闭继承的文件描述符。

fork

子进程对文件表项的修改,会不会影响父进程?

  • shell进程启动时,会自动打开这三个文件描述符(可能由配置项决定);
  • shell利用fork()开启用户进程(子进程),该子进程复制父进程shell的所有文件描述符,于是0, 1, 2文件描述符被打开;
  • 由于子进程共享父进程的文件表项,子进程对文件状态标志(读、写、同步或非阻塞等)、文件偏移量的修改,将会影响父进程

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define err_sys(x) \
{ \
perror(x); \
exit(1); \
}

void pr_fl(int fd); // 自定义函数:打印文件状态标志
void set_fl(int fd, int flags); // 自定义函数:设置文件状态标志

int main() {
pr_fl(0);

set_fl(0, O_APPEND);
pr_fl(0);

return 0;
}

void set_fl(int fd, int flags) {
int val;

if ((val = fcntl(fd, F_GETFL, 0)) < 0)
err_sys("fcntl F_GETFL error");

val |= flags;

if (fcntl(fd, F_SETFL, val) < 0)
err_sys("fcntl F_SETFL error");
}

void pr_fl(int fd) {
int val;

// do not guarantee success on certain system, check EINVAL first
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
err_sys("fcntl F_GETFL error");

switch (val & O_ACCMODE) {
case O_RDONLY:
printf("read only");
break;
case O_WRONLY:
printf("write only");
break;
case O_RDWR:
printf("read write");
break;
default:
err_sys("unknown open type");
}

if (val & O_CREAT)
printf(", create");
if (val & O_APPEND)
printf(", append");
if (val & O_NONBLOCK)
printf(", non-block");
if (val & O_SYNC)
printf(", synchronized file");
// if (val & O_DSYNC)
// printf(", synchronize data");

putchar('\n');
}
  • 第一次运行:
1
2
3
$ ./a.out
read write
read write, append
  • 第二次运行:
1
2
3
$ ./a.out
read write, append
read write, append
  • 分析

    • 第二次运行时,文件描述符0的初始状态保持了第一次运行的结果!
    • 这是因为父进程shell的文件表项的文件状态标志被子进程a.out改变了。
  • 第三次运行:

    重新启动shell,并运行a.out

1
2
3
$ ./a.out
read write
read write, append
  • 分析

    • 第三次运行,结果与第一次一致,这说明我们的猜测正确。
    • 父进程shell关闭之后,所有文件描述符被关闭,文件IO被关闭,文件表被释放。重启shell也就重置了文件表。
  • 引申:
    在此我们注意到,文件描述符0, 1, 2(标准输入、标准输出、标准错误)在一个shell及其所有子进程中,对应的文件(设备)是同一个。由于共享了文件表项,指向了同一个v-node表项,故都指向同一个虚拟终端。这与我们的平时观察一致,不然shell运行程序时,输入输出的入口在哪里呢?

如果进程打开文件,此时我们使用 rm / unlink 删除文件,会发生什么?

什么也不会发生。因为 Linux 文件系统的设计允许文件名(目录项)和文件内容(inode)分离。只有当所有引用(包括文件描述符和内存映射)都关闭后,inode 才会被删除。

在 Linux 中,一个文件由三部分组成:

  • 目录项(filename):比如 /lib/libexample.so
  • inode(元数据):记录权限、大小、时间戳等
  • 数据块(内容):实际的文件内容

rm 只是删除了目录项(文件名),并没有删除 inode 或数据块,只要还有进程引用它。

引用 inode 的方式包括:

  • 打开文件(open())
  • 映射文件(mmap())
  • 动态链接器加载 .so 文件

这些引用会让内核知道:这个 inode 仍然在使用中,不能释放。

这是为了支持非常重要的行为:

✅ 允许进程继续使用已打开或已映射的文件,即使文件名被删除。

这在很多场景下非常有用:

  • 日志轮转:删除旧日志文件,进程仍在写入
  • 安全性:防止其他进程访问文件名,但当前进程仍可使用
  • 临时文件:创建后立即删除,只让当前进程使用

在 Linux 内核中,每个 inode 结构体有一个字段 i_count,表示该 inode 当前被引用的次数。这个引用包括:

  • 被文件系统挂载
  • 被进程打开
  • 被内核缓存使用

这个字段不是用户空间可以直接查看的,但你可以通过以下方式间接观察:

方法 能看到什么
ls -li inode 号 + 硬链接引用计数
lsof -p <PID> | grep / fuser </path/to/so> 是否有进程打开文件
/proc/<PID>/fd/ 查看文件描述符引用
/proc/<PID>/maps 查看映射
ldd 查看可执行文件依赖的 .so
strace 跟踪运行时加载行为
内核字段 i_count 真实引用计数(需内核调试)

在本地文件系统(如 ext4)中:

  • 即使文件正在使用,rm 也能删除目录项
  • 文件内容仍保留在 inode 中,直到所有引用关闭

但在 NFS 文件系统 中:

  • 客户端不能立即删除正在被使用的文件
  • 所以它会将文件重命名为 .nfsXXXX
  • 等引用释放后,自动删除该临时文件

所以此时如果 rm -rf 目录,但是目录下某文件被使用,会提示 xxx/.nfs000000004ec2d5e70000da89

1
2
$ lsof -p <PID> | grep .nfs
my_executable 283964 my_name mem REG 0,183 18371240 1321391591 /XXX/.nfs000000004ec2d5e70000da89 (xxx:/yyy/zzz)

因为 so 被手动删除,此时引用的 so 被重命名成 .nfsXXXX

手动删除 .so 文件后,系统生成了 .nfsXXXX 文件,但进程仍然能继续使用它。进程怎么知道新文件名?

答案是:进程根本不知道新文件名,也不需要知道。

当一个进程打开一个文件(比如 libexample.so),它获得的是一个 文件描述符(fd),这个描述符指向的是内核中的 inode,而不是文件名。

.nfsXXXX 文件名是给谁看的?

它是 NFS 客户端自动创建的临时文件名,用于:

  • 保留 inode 内容,直到所有引用关闭
  • 让系统知道这个文件还不能真正删除
  • 让你可以用 lsof 或 fuser 查找谁在使用它

📌 这个文件名不会被通知给进程,也不会影响进程的运行。

正常情况下:进程关闭后 .nfsXXXX 自动消失

  • .nfsXXXX 文件是由 NFS客户端 创建的临时文件
  • 当某个文件被打开后删除,客户端会将其重命名为 .nfsXXXX
  • 一旦该文件的 打开引用计数为 0(即所有进程都关闭了该文件),客户端会自动删除 .nfsXXXX

⚠️ 异常情况:文件可能残留

如果出现以下情况,.nfsXXXX 文件可能不会自动删除:

  • 客户端 crash 或断网,未能完成清理动作
  • 使用 kill -9 强制终止进程,绕过了正常关闭流程
  • NFS 客户端或服务器之间同步延迟
  • 文件被多个进程同时打开,只有部分进程关闭

在这些情况下,.nfsXXXX 文件会残留在文件系统中,直到手动清理。

管道

通过上文的叙述,我们很容易想到管道本质上也是一种特殊的文件,所以管道机制之所以可以进程间通信也是根据共享文件表项保证的。
管道和文件进行进程间通信的本质相同。

Linux 文件锁与记录锁

TODO

参考链接:链接1链接2

参考

  • 《UNIX 环境高级编程》
  • 《Linux 内核设计与实现(原书第 3 版) - Linux Kernel Development, Third Edition》,(美)拉芙(Love, R.)著;陈莉君,康华译. ——北京:机械工业出版社,2011.9(2021.5 重印)
  • 图解进程控制块stask_struct

Unix 权限涉及三个部分:** 用户 进程 文件 **。
权限分为常用权限、SELinux 权限。
manpage: man 2 stat 中搜索 “mode” 可以看到几种常用权限的详情。

用户和分组

用户用 user ID 区分。多个用户可以划入同一个用户分组,一个用户可以同时属于不同的分组。这就是 UID(User ID)和 GID(Group ID)。

现在我将使用我的凭据登录到 shell 并运行:

1
grep $LOGNAME /etc/passwd

rotem: x:1000:1000:rotem,,,:/home/rotem:/bin/bash

您可以看到我的日志名 (rotem)、均为 1000 的 UID 和 GID,以及其他详细信息,例如我登录的 shell。

进程的用户 ID (UID)

每个进程都有一个所有者,并且每个进程都属于一个组。

进程有 3 种 UID:real user IDeffective user IDsaved user ID。其中还有一个 set-user-ID 的概念,这个概念和 effective user ID 紧密关联。

实际用户 ID (RUID, Real User ID) [^5]

在我们的 shell 中,我们现在将运行的每个进程都将继承我的用户帐户的权限,并将使用相同的 UID 和 GID 运行。

当您 fork 一个新进程时,该进程会继承父进程的 RUID。通常父级的 RUID 是你的 shell 并且它有当前登录用户的 UID。所以新进程有当前登录用户的 UID 的 RUID。通常这不会改变,只有 root 可以改变它。

举个例子,想想 init 进程派生了你的登录 shell。在 fork 期间,shell 将具有 root 的 RUID(因为 shell 的父级是 init)。但是,init 进程使用 /etc/passwd 将 shell 的 RUID 改成你的 UID. 因此,此后登录 shell 的 RUID 将是您的 UID,而不是 root。所以,我们可以说 RUID 是进程所有者的。

让我们运行一个简单的命令来检查它:

1
2
$ sleep 100 & ps aux | grep 'sleep'
bi-an 3741 0.0 0.0 11252 928 pts/0 S 17:00 0:00 sleep 100

然后根据 ps 命令打印出的 PID (3741) ,查进程 UID 和 GID:

1
2
$ stat -c "%u %g" /proc/3741
1000 1000

然而,系统判断一个进程对一个文件是否有权限时,要验证的 ID 是 effective user ID,而不是 real user ID。

有效用户 ID(EUID, Effective User ID)

Linux 通常都不建议用户使用 root 权限去进行一般的处理,但是普通用户在做很多很多 services 相关的操作的时候,可能需要一个特殊的权限。为 了满足这样的要求,许多 services 相关的 executable 有一个标志,这就是 set-user-ID bit。当这个 set-user-ID bit=ON 的时候,这个 executable 被用 exec 启动之后的进程的 effective user ID 就是这个 executable 的 owner id,而并非 parent process real user id。如果 set-user-ID bit=OFF 的时候,这个被 exec 起来的进程的 effective user ID 应该是等于进程的 user ID 的。
我们以 ping 命令为例。

使用 which 命令搜索二进制位置,然后运行 ls -la

-rwsr-xr-x 1 root root 64424 Mar 10 2017 ping

可以看到文件的所有者和组是 root. 这是因为该 ping 命令需要打开一个套接字,而 Linux 内核 root 为此需要特权。

但是,如果没有 root 特权,我如何使用 ping

注意文件权限的所有者部分中的 “s” 字母而不是 “x”。

这是特定二进制可执行文件(如 pingsudo)的特殊权限位,称为 set-user-ID

这是 EUIDEGID 发挥作用。

将会发生的情况是,当执行设置了 setuid 的二进制文件 ping 时,该进程将其有效用户 ID (EUID) 从默认值 RUID 更改为此特殊二进制可执行文件的所有者,在本例中为 root。

这一切都是通过这个文件有这个简单的事实来完成的 set-user-ID

内核通过查看进程的 EUID 来决定该进程是否具有特权。因为现在 EUID 指向 root,操作不会被内核拒绝。

注意:在最新的 Linux 版本中,ping 命令的输出看起来会有所不同,因为它们采用了 Linux Capabilities 方法而不是这种 setuid 方法(对于不熟悉的人)请阅读 此处

set-user-ID

参考 链接 1

Unix 包含另一个权限位,即该权限 set-user-ID 位。如果为可执行文件设置了该位,那么只要所有者以外的用户执行该文件,该用户就可以访问所有者的其他任何文件,从而获得所有者的所有文件读 / 写 / 执行特权!

这会导致运行该文件的任何人或进程都可以访问系统资源,就好像他们是该文件的所有者一样。

1
2
$ ls -l testfile
-rw-rw-r-- 1 rotem rotem 0 Nov 8 17:12 testfile

为文件添加 set-user-ID 权限:

1
2
3
$ sudo chmod u+s testfile
$ ls -l testfile
-rwSrw-r-- 1 rotem rotem 0 Nov 8 17:12 testfile

说明:大写 S 表示,有 set-user-ID 权限,但是没有执行权限。

set-group-ID

阅读 Manual:man 2 stat

The set-group-ID bit (S_ISGID) has several special uses.
For a directory, it indicates that BSD semantics is to be used for that directory: files created there inherit their group ID from the directory, not from the effective group ID of the creating process, and directories created there will also get the S_ISGID bit set.

如果目录具有设置组 ID(S_ISGID):

  • 其下创建的文件将从其父目录的继承组 ID,而不能从创建其的进程中继承有效组 ID;
  • 其下创建的子目录将继承设置组 ID 位(S_ISGID)。

For a file that does not have the group execution bit (S_IXGRP) set, the set-group-ID bit indicates mandatory file/record locking.

如果一个文件有 “设置组 ID(set-group-ID)” 但是没有 “组执行权限(S_IXGRP)”,也就说具有如下权限:

1
2
% ls -l a.txt
-rw-r-Sr-- 1 username groupname 0 Feb 23 19:34 a.txt

那么,此时 set-group-ID 位喻示强制文件 / 记录锁。

TODO:强制文件 / 记录锁是什么?
Mandatory File Locking
Why remove group execute for mandatory file lock?

粘滞位:

The sticky bit (S_ISVTX) on a directory means that a file in that directory can be renamed or deleted only by the owner of the file, by the owner of the directory, and by a privileged process.

大写 T 表示,有 restricted deletion flag or sticky bit(粘滞位),但是没有执行权限,t 权限只对目录有效,作用是保护目录项不能被其他用户删除。目录要同时具有 xs 才能保证粘滞位有效。

保存的用户 ID (SUID, Saved User ID)

为什么要设置一个 saved set-user-ID 呢?它的意义是,它相当于是一个 buffer, 在 exec 启动进程之后,它会从 effective user ID 位拷贝信息到自己。

  • 对于非 root 用户,可以在未来使用 setuid() 来将 effective user ID 设置成为 real user ID 和 saved set-user-ID 中的任何一个。但是非 root 用户是不允许用 setuid() 把 effective user ID 设置成为任何第三个 user id。
  • 对于 root 来说,就没有那么大的意义了。因为 root 调用 setuid() 的时候,将会设置所有的这三个 user ID 位。所以可以综合说,这三个位的设置为为了让 unprivilege user 可以获得两种不同的 permission 而设置的。

《Unix 环境高级编程》的例子是,普通用户去执行一个 tip 进程,set-user-ID bit=ON,执行起来的时候,进程可以有 uucp (executable owner) 的权限来写 lock 文件,也有当前普通用户的权限来写数据文件。在两种文件操作之间,使用 setuid() 来切换 effective user id。但是正是因为 setuid() 的限制,该进程无法获得更多的第三种用户的权限。

saved set-user-ID 是无法取出来的,是 kernel 来控制的。注意 saved set-user-ID 是进程中的 id,而 set-user-ID bit 则是文件上的权限。

总结

用户 ID:

属性 决定特权 说明
EUID ✅ 是 内核权限检查时使用
RUID ❌ 否 表示谁启动了进程
FSUID ⚠️ 有时 文件访问权限相关
SUID ⚠️ 有时 用于权限恢复

组 ID:

属性 说明 用途
EGID 有效组 ID 用于权限检查
RGID 实际组 ID 表示谁启动了进程
SGID 保存组 ID 用于权限恢复
FSGID 文件系统组 ID 文件访问专用

以上都是讨论用户 ID,如果没有特殊说明,以上的组 ID 和用户 ID 基本是类似的,只是作用对象为组。

文件权限

符号形式的权限(Symbolic permissions)

符号形式表示文件权限有 5 种:rwxst

  • r:可读。对文件来说,意味着能执行 vim 查看、cat 等。对目录来说,意味着能执行 ls 查看其下的文件列表。

  • w:可写。对文件来说,意味着能执行 vim 等工具编辑并保存。对目录来说,意味着能够创建、删除文件或新的目录。

  • x:可执行(文件) / 可搜索(目录)。对文件来说,意味着可以执行。对目录来说,意味着能够 cd 进入该目录。

《UNIX 环境高级编程》P80 中如此描述:

读权限允许我们读目录,获得该目录中所有文件名的列表。当一个目录是我们要访问文件的路径名的一个组成部分时,对该目录的执行权限使我们可以通过该目录(也就是搜索该目录,寻找一个特定的文件名)。

ls 没有可搜索权限的目录 可以看到文件列表、文件类型,但是不能看到其他信息,比如文件权限、所有者、大小、修改时间等,因为这些信息保存在 inode 中,必须先 cd 进入该目录,才能读取这些信息。同样,ls -R 不能显示没有执行权限的目录下的子目录下的文件,因为这也必须先 cd 该目录,然后执行 ls 显示子目录的文件。

1
2
3
4
5
6
7
8
$ ls -lR mydir/
mydir/:
ls: cannot access 'mydir/dir2': Permission denied
ls: cannot access 'mydir/file2': Permission denied
total 0
d????????? ? ? ? ? ? dir2
-????????? ? ? ? ? ? file2
ls: cannot open directory 'mydir/dir2': Permission denied

给目录递归恢复权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ chmod -R u+X mydir/
$ ls -lR mydir/
mydir/:
total 4
drwxrwxr-x 3 rotem rotem 4096 Nov 9 10:02 dir2
-rwxrw-r-- 1 rotem rotem 0 Nov 9 10:03 file2

mydir/dir2:
total 8
-rwxrw-r-- 1 rotem rotem 10 Nov 8 22:55 1.txt
-rwxrw-r-- 1 rotem rotem 0 Nov 8 22:55 2.txt
drwxrwxr-x 2 rotem rotem 4096 Nov 9 10:05 dir3

mydir/dir2/dir3:
total 0
-rwxrw-r-- 1 rotem rotem 0 Nov 9 10:05 3.txt
  • s:即 set-user-ID 权限,如果可执行文件有 s 权限属性,那么任意进程执行该文件时,将自动获得该文件所有者相同的所有权限。如果文件没有 x 权限,却有 s 权限,那么 ls -l 命令将该文件显示为大写的 S。文件只有同时具备 s 权限和 x 权限,才有意义,因为一个文件要应用 set-user-ID 属性,首先要保证其可执行。

例如 ping 文件:

1
2
$ ls -l /bin/ping
-rwsr-xr-x 1 root root 44168 May 8 2014 /bin/ping

由于设置了 s 权限,所以任何文件都能以 root 用户的身份运行,也就被内核允许打开套接字。

  • t:即 restricted deletion flag or sticky bit,称为 “粘滞位” 或 “限制删除标记”。仅仅对目录有效,对文件无效。在一个目录上设了 t 权限位后,(如 /home,权限为 1777) 任何的用户都能够在这个目录下创建文档,但只能删除自己创建的文档 (root 除外),这就对任何用户能写的目录下的用户文档 启到了保护的作用。如果目录 / 文件没有 x 权限,却有 s 权限,则 ls -l 命令将目录 / 文件显示为大写的 T。目录只有同时具备 t 权限和 x 权限,才有意义,因为一个目录如果本来就不允许增删目录项(x 权限),删除其他用户的文件更无须提了。

    • 当一个目录设置了 t 权限时:
      • 所有用户都可以在该目录中创建文件(如果有写权限)
      • 但只能删除自己创建的文件(当然要有写权限,否则也不能创建文件)
      • root 用户除外,始终可以删除任何文件

例如:/tmp/var/tmp 目录供所有用户暂时存取文件,亦即每位用户皆拥有完整的权限进入该目录,去浏览、删除和移动文件。

数字形式的权限(Numeric permissions)

可以用 4 位八进制数(0-7)表示这些文件权限,由 4、2、1 相加得到,0 表示所有权限都没有。

这 4 位的含义如下:

  • 第 1 bit:4 表示 set-user-ID,2 表示 set-group-ID,1 表示 restricted deletion or sticky 属性(粘滞位);
  • 第 2 bit:表示文件所有者的权限:可读(4)、可写(2)、可执行(1);
  • 第 3 bit:表示文件所属组的权限:可读(4)、可写(2)、可执行(1);
  • 第 4 bit:表示其他用户的权限:可读(4)、可写(2)、可执行(1)。

以下是 chmod 的 man page 的说明 [^2]:

A numeric mode is from one to four octal digits (0-7), derived by adding up the bits with values 4, 2, and 1. Omitted digits are assumed to be leading zeros. The first digit selects the set user ID (4) and set group ID (2) and restricted deletion or sticky (1) attributes. The second digit selects permissions for the user who owns the file: read (4), write (2), and execute (1); the third selects permissions for other users in the file’s group, with the same values; and the fourth for other users not in the file’s group, with the same values.

相关命令

ls 命令

ls -l 命令用于查看文件权限。

chmod 命令

chmod 命令用于改变文件权限。

基本用法:

1
2
3
chmod [OPTION]... MODE[,MODE]... FILE...
chmod [OPTION]... OCTAL-MODE FILE...
chmod [OPTION]... --reference=RFILE FILE...

** 大写 X 参数 ** ^1

例如 chmod u+X filenamechmod u-X filename

chmod 的 man page 中介绍如下:

The letters rwxXst select file mode bits for the affected users: read (r), write (w), execute (or search for directories) (x), execute/search only if the file is a directory or
already has execute permission for some user (X)
, set user or group ID on execution (s), restricted deletion flag or sticky bit (t) [^2].

加黑体的话很费解,但是又十分准确,解释如下:

  1. 对所有目录赋予执行权限,这意味着可以执行 cd

  2. 对所有文件,如果原来文件的 ugo(user / group / others)任意一个原先有执行权限,那么动作与小写 -x 参数相同;如果原先没有,那么忽略。例如:

    1
    ls -l

    结果:

    -rw-rw-r– 1 rotem rotem 0 Nov 9 10:55 file1
    -rw-rw-r-x 1 rotem rotem 0 Nov 9 10:56 file2

    可以看到,原来 file1 的 ugo 都不具备执行权限,file2 的 others 具备执行权限。

    • 对 file1 执行 X 动作,将无效:
    1
    2
    sudo chmod u+X file1
    ls -l file1

    -rw-rw-r– 1 rotem rotem 0 Nov 9 10:55 file1

    • 但是对 file2 执行 X,能够生效:
    1
    2
    sudo chmod u+X file2
    ls -l file2

    -rwxrw-r-x 1 rotem rotem 0 Nov 9 10:56 file2

    题外话: chmod -R u-X mydir 该命令无法递归执行,因为当执行完顶层目录的权限更改之后,已经没有权限 cd 顶层目录了,其他执行全部被停止。

  • getfacl/setfacl
  • umask

SELinux 权限

SELinux 提供更为严格的访问控制。
可以用 ls -Z 查看文件的 SELinux 权限(安全上下文)。这部分将来另用一篇博客说明。暂时可以参考文献 [^3]。

参考文献

[^2]: chmod 的 man page
[^3]:https://www.jianshu.com/p/73621cc7c222
[^4]:https://en.wikipedia.org/wiki/User_identifier#Saved_user_ID
[^5]:https://stackoverflow.com/questions/32455684/difference-between-real-user-ID-effective-user-ID-and-saved-user-ID
[^6]:https://cloud.tencent.com/developer/article/1722142

系统文件

/etc/services: 端口列表
/etc/protocols: 协议列表

socket 参数

SO_REUSEADDR

主要功能:允许端口重用。客户端一般不用,只在服务端常见。
更准确地说,它有几个具体效果(以 TCP 为例):

TIME_WAIT 状态下可重绑定

正常情况下,当服务端关闭套接字,端口进入 TIME_WAIT 状态(持续 ~1-4 分钟)

如果不设置 SO_REUSEADDR,你必须等 TIME_WAIT 结束才能再次 bind() 相同端口

设置后,可以立即重新 bind()

多个套接字绑定到同一个端口(但 IP 必须不同)

常见于多播、广播,或者一台机器上多个不同地址绑定同一个端口

Linux 特性:允许 相同 IP 和端口 多个套接字同时监听(结合 SO_REUSEPORT 使用更常见,nginx 就依赖这个做负载均衡)。

TIME_WAIT

TIME_WAIT 只会出现在主动关闭连接的一方。

一般情况:客户端主动关闭 → 客户端 TIME_WAIT,服务端不需要考虑

特殊情况:如果服务端主动关闭 listen_fd(例如服务进程退出后重启),就会产生 TIME_WAIT,需要优化手段。

SO_REUSEPORT

多进程/线程共享端口(同一IP+端口),避免 TIME_WAIT 堆积影响单个进程。前提是都设置了 SO_REUSEPORT)。

内核会 均匀分发新连接 到这些套接字(负载均衡)。

常见用途:

  • 高性能网络服务(nginx、redis、haproxy 等)
  • 利用多进程/多线程提升网络吞吐量

与 SO_REUSEADDR 的区别

选项 功能 使用场景
SO_REUSEADDR 允许端口在 TIME_WAIT 状态下重用 服务端重启,避免 “Address already in use”
SO_REUSEPORT 允许同一端口被多个进程/线程同时绑定,内核负载均衡 高性能多进程网络服务
  • SO_REUSEADDR → 解决 TIME_WAIT 问题
  • SO_REUSEPORT → 解决 多进程监听同一端口的负载均衡

TCP_NODELAY

用于关闭 Nagle 算法。

  • 背景:Nagle 算法

    • Nagle 算法的作用:

      把很多小的 TCP 包合并成一个大包再发送,以减少网络中小包的数量,提高效率。

      规则:如果前一个包还没被确认(ACK),新的小包不要立刻发送,而是先缓存,等到收到 ACK 或者缓冲区积累够大时再发。

      1. 如果要发送的数据很大(≥ MSS,最大报文段长度),直接发。
      2. 如果应用要发小数据:
        • 有未确认的包 → 暂时把新数据放在缓冲区里,不发。
        • 收到了 ACK → 把缓存的数据打包一起发送。
    • 代价:

      会造成 延迟(例如即时通信、RPC 请求这种场景,一次 send() 可能会等下一个小包一起发)。

✅ 建议使用的场景:

  • RPC 框架
  • 即时通讯(IM)
  • 游戏服务器(低延迟要求)
  • 高频短小消息的交互

❌ 不建议使用的场景:

  • 大文件传输(比如 HTTP 下载)
  • 视频流、音频流(关闭 Nagle 反而降低效率)

SO_KEEPALIVE

开启 SO_KEEPALIVE 后,内核在后台做三件事(以 Linux 默认值为例,可能因系统不同而不同):

  • tcp_keepalive_time(默认 7200s = 2小时)
    如果一个连接在 tcp_keepalive_time 时间内都没有任何数据往来,内核会开始发送探测包。

  • tcp_keepalive_intvl(默认 75s)
    探测包之间的间隔。

  • tcp_keepalive_probes(默认 9次)
    如果连续 tcp_keepalive_probes 次探测都没有回应,内核会认为连接已经断开,并通知应用层 read()/recv() 返回 0 或 ECONNRESET。

可以通过 /proc/sys/net/ipv4/tcp_keepalive_* 修改这些参数:

1
2
3
4
5
6
cat /proc/sys/net/ipv4/tcp_keepalive_time
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
cat /proc/sys/net/ipv4/tcp_keepalive_probes

# 修改方式
sysctl -w net.ipv4.tcp_keepalive_time=600

应用场景

  • 长连接 RPC、心跳检测:避免死连接无限挂着。
  • 服务端防止资源泄漏:客户端异常掉线时,服务端能最终释放连接。
  • 中间设备 NAT/防火墙:如果链路长时间无流量,可能被踢掉,Keepalive能保持活动状态(但注意默认周期太长,往往要调低)。

RESET vs KeepAlive

  • 客户端正常断开

    • 客户端调用 close() 或 shutdown()

    • 会向服务端发送 FIN,服务端的 read() 返回 0

    • 这是“主动优雅关闭”,服务端能马上感知

      ✅ 这种情况下不需要 SO_KEEPALIVE

  • 客户端异常掉线(断电、拔网线、进程挂掉)

    • TCP 不能立即知道对方掉线

    • 为什么?

      • TCP 是端到端协议,除非收到 RST 或 FIN,否则内核认为连接仍然存在
      • 异常掉线不会发送 FIN
      • 网络异常(如网线拔掉)也不会发送 RST
      • 这时服务端的 read() / write() 不会马上报错
      • 写时可能阻塞
      • 读时可能一直阻塞

      ✅ 所以需要 SO_KEEPALIVE 来让内核周期性探测,最终发现对方掉线

  • 客户端发送 RST 的情况

    • RST 只在一些场景出现:
      • 客户端向已经关闭的套接字写数据
      • 本地进程调用 abort()
    • 但 异常掉线(掉电、断网、进程被 kill -9)不会发 RST
    • 因此 服务端不能依赖 RST 来发现死连接
场景 服务端能否立即发现 是否需要 Keepalive
客户端正常 close()
客户端异常掉线(断电、拔网线)
客户端本地 abort() 或 write 已关闭套接字 是(会收到 RST)

所以 SO_KEEPALIVE 主要用于发现客户端异常掉线。没有它,长连接可能永远挂在 ESTABLISHED,资源泄漏。

参考

端口0的作用

用户空间和内核空间是隔离的

切换内核态和用户态为什么要内存复制?

问题 描述
安全性 用户程序可能传入非法地址,导致内核崩溃或被利用攻击
稳定性 用户程序可能在 poll() 返回前修改数组,导致内核读取不一致
内存管理 用户空间内存可能被 swap 出或者释放,内核无法保证访问有效

内核态

我们在说“切换到内核态”时,其实指的是 CPU 特权级别从用户态(ring3)切换到内核态(ring0) 的过程。

用户态 vs 内核态

用户态(user mode)

应用程序(比如你写的 C++ 程序)运行的环境。

权限受限,不能直接操作硬件(如磁盘、网卡),也不能随便访问内核内存。

只能通过 系统调用 (syscall) 向内核请求服务。

内核态(kernel mode)

操作系统内核运行的环境。

拥有最高权限(ring0),可以操作 CPU 指令集、内存管理、驱动、硬件寄存器。

系统调用的实现代码就在内核态里。

“切换到内核态”的过程

当你调用一个系统调用,比如:

read(fd, buf, size);

你的程序在 用户态,调用 read()。

实际上 read() 会触发一条特殊指令(例如 Linux x86-64 用 syscall 指令)。

CPU 捕捉到这个指令,自动:

从用户态切换到内核态。

切换到内核栈。

保存用户态寄存器上下文。

跳到系统调用处理函数(比如 sys_read)。

内核态代码执行 sys_read,比如访问文件系统、检查 socket buffer。

处理完后返回,CPU 再切回用户态,恢复上下文,继续执行应用代码。

🔹 为什么要区分用户态/内核态?

安全:用户程序不能直接操作硬件。

稳定性:即使用户程序崩溃,内核和其他进程不会受影响。

性能隔离:内核提供抽象(系统调用接口),避免应用直接干扰底层资源。

✅ 所以,总结一句:
“切换到内核态”就是 CPU 从运行普通用户代码(权限受限)切换到执行内核代码(最高权限)的过程,常常发生在系统调用、异常、硬件中断时。

1. 左值、将亡值、纯右值

C++11的值必定属于:左值、右值(将亡值、纯右值)三者之一。不是左值就是右值。详见值类别。

  • 左值的特点:“有名字、可以取址”。没有名字或者不能取址,则必定是右值。
  • 右值的特点:即将消亡,也就是说“会被析构”。
    • 纯右值:一定没有名字。比如除去string之外字面值常量、函数返回值、运算表达式。
    • 将亡值:即将消亡的值:比如临时变量,一旦离开作用域就会被销毁;可能没有名字,例如函数的返回值(非引用)。

示例:

1
2
3
4
5
int main() {
A(); // 匿名对象的作用域仅限于语句中,一旦离开当前语句,就会析构。
getchar(); // 暂停
return 0;
}

2. 引用、右值引用

右值引用涉及“右值”和“引用”两个概念。

  • 引用不是对象,所以定义一个“右值引用”不会调用构造函数,避免了多余的构造过程。
  • 右值是即将析构的值,把右值绑定到右值引用上,延长了右值的生命期,所以右值对象没有析构。

右值引用规则:

  • 可以把左值绑定到左值引用。
  • 可以把右值绑定到右值引用。
  • 不允许把左值绑定到右值引用。
  • 不允许把右值绑定到左值引用。
  • const左值引用可以接受左值或右值。

示例:

1
2
3
int a1 = 10; // 10是纯右值
const int& aa = 10; // 常量引用可以接受右值
int&& aaa = 10; // 右值引用接受右值

3. 引用和右值引用是左值

引用(包括右值引用)本身是左值,可以取址,但不能对右值取址。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <utility>
using namespace std;

void fun1(int& t) { // 接受一个左值参数
}

void fun2(int&& t) { // 接受一个右值参数,但t本身是左值
}

int main() {
int a = 10;
int&& ra = move(a); // move(a)返回一个右值,ra却是一个左值

fun1(ra); // 正确:ra是左值,可以绑定到左值引用
fun2(move(a)); // 正确:move(a)返回一个右值

return 0;
}

4. 复制构造函数和移动构造函数

为什么右值引用的构造函数被视为“移动”语义?

因为输入参数是一个引用(右值引用也是引用),可以直接访问所引对象的资源并接管它,同时将源对象的资源置空。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

class A {
public:
A() { cout << "A()" << endl; }
A(const A&) { cout << "A(const A&)" << endl; }
A(A&&) { cout << "A(A&&)" << endl; }
};

int main() {
A a;
A b(std::move(a)); // 调用移动构造函数
return 0;
}

5. 完美转发

完美转发是指对模板参数实现完美转发:即输入什么类型(左值、右值)的参数,就是什么类型的参数。

引用折叠规则:

  • 如果有左值引用,优先折叠成左值引用。
  • 如果只有右值引用,参数推导成右值引用。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

void RunCode(int& m) { cout << "lvalue ref" << endl; }
void RunCode(int&& m) { cout << "rvalue ref" << endl; }

template<typename T>
void PerfectForward(T&& t) {
RunCode(static_cast<T&&>(t)); // 保证完美转发
}

int main() {
int a = 10;
PerfectForward(a); // lvalue ref
PerfectForward(move(a)); // rvalue ref
return 0;
}

6. 移动构造函数、移动赋值函数、复制构造函数、复制赋值函数

移动构造函数的注意事项:

  • 移动构造函数不允许抛出异常,建议添加noexcept关键字。
  • 使用std::move_if_noexcept可以在移动构造函数抛出异常时回退到复制构造函数。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

class A {
public:
A() { cout << "A()" << endl; }
A(const A&) { cout << "A(const A&)" << endl; }
A(A&&) noexcept { cout << "A(A&&)" << endl; }
};

int main() {
A a;
A b(std::move(a)); // 调用移动构造函数
return 0;
}

7. 编译器优化

编译器默认会采用“返回值优化”(RVO或NRVO)。要观察移动语义与复制语义的不同,应该关闭编译器优化。

关闭优化命令:

1
g++ -o test main.cc -fno-elide-constructors

8. 合成的移动操作

如果没有定义复制构造/赋值函数,编译器会为我们合成(浅复制)。但如果自定义了复制构造函数、复制赋值运算符或析构函数,编译器将不会合成移动构造/赋值函数。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

class A {
public:
A() { cout << "A()" << endl; }
A(const A&) { cout << "A(const A&)" << endl; }
A(A&&) { cout << "A(A&&)" << endl; }
};

int main() {
A a;
A b(std::move(a)); // 调用移动构造函数
return 0;
}

9. std::move的实现

std::move是一个类型转换,没有完成其他工作。

实现:

1
2
3
4
template<class T>
constexpr typename std::remove_reference<T>::type&& move(T&& t) noexcept {
return static_cast<typename std::remove_reference<T>::type&&>(t);
}

10. unique_ptrstd::move

示例:

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <memory>
using namespace std;

int main() {
unique_ptr<int> up(new int(10));
unique_ptr<int> p = std::move(up); // 现在up为空
return 0;
}

解释:std::move调用unique_ptr的移动构造函数,转移up所拥有的资源,并将up置为空。


11. 右值与sizeof

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct A {
int x, y;
};

int f() {
return 1;
}

int main() {
cout << sizeof(int()) << endl; // 1
cout << sizeof(10) << endl; // 4
cout << sizeof(A) << endl; // 8
cout << sizeof(A()) << endl; // 1
cout << sizeof(f()) << endl; // 4
}

参考资料

  • 《深入理解C++11: C++新特性解析与应用》
  • 《C++ Primer 第五版》
  • C++中文 - API参考文档

问题描述

代码:

1
2
3
4
5
6
7
8
9
getaddrinfo(localhost, "sunrpc", &hints, &result); // "sunrpc" 或 端口 111 都可以
for (const auto *rp = result; rp != nullptr; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock == -1) continue;
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break; // Success
perror("connect failed");
close(sock);
sock = -1;
}

这段代码,connect() 返回 -1 ,报错为 Protol not available

  • 但是我们明明是通过 getaddrinfo() 查询到的地址信息,为什么报错?
  • 这个报错也很具有误导性,我们开启了 IPv4 ,没有开启 IPv6,如果开启 IPv6,这个错误会消失,不支持 IPv4

排查过程

运行这些命令:

  • hostname
  • hostname -f
  • hostname -a
  • hostname -I
  • hostnamectl
  • cat /proc/sys/kernel/hostname
  • more /etc/host*
  • /sbin/ifconfig -a
1
2
3
4
5
6
7
$ hostname
$ cat /etc/hosts
# Created by chnetinfo.sh.
# Do not remove the following line, or various programs
# that require network functionality will fail.
::1 localhost.localdomain localhost
xx.xxx.xxx.xx xiaoming-PC xiaoming-PC.xiaoming-company.com

注:上面 cat /etc/hosts 的第二个 IP 进行了个人信息隐藏。xx 代表数字。

说明:

地址 协议版本 作用
127.0.0.1 IPv4 本地回环地址,用于本机内部通信
::1 IPv6 本地回环地址,用于本机内部通信

于是问题找到了:/etc/hosts/ 只配置了 ::1 ,那么使用 IPv4 协议尝试 connect localhost 就会返回 -1 。

Bazel简介

Bazel 是 Google 开发并开源的一款构建工具(build system),主要用来自动化编译、测试和打包大型软件项目。

  • 高速构建:相当于智能化的Make
  • 可复现构建:通过严格的声明式 BUILD 文件,确保每次构建结果一致。
  • 跨平台:支持 Linux、macOS、Windows 等多个操作系统。
  • 支持多语言:不只支持 C++,还支持 Java、Python、Go、Shell 等多种语言的项目构建。

安装Bazel

方法1:apt 镜像源

清华 apt 镜像源:

1
2
3
sudo tee /etc/apt/sources.list.d/bazel.list <<EOF
deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/bazel-apt stable jdk1.8
EOF

注:jdk1.8https://mirrors.tuna.tsinghua.edu.cn/bazel-apt/dists/stable/下的一个目录。
如果提示找不到对应的路径,就去查看该目录是否存在。

导入清华镜像的 GPG key:

1
curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/bazel.gpg > /dev/null

更新并安装:

1
2
3
sudo apt update
sudo apt install bazel
bazel --version

方法 2:直接下载二进制(绕过 apt)

从 GitHub Release 下载:

1
2
3
4
wget https://github.com/bazelbuild/bazel/releases/download/6.5.0/bazel-6.5.0-linux-x86_64
chmod +x bazel-6.5.0-linux-x86_64
sudo mv bazel-6.5.0-linux-x86_64 /usr/local/bin/bazel
bazel --version

方法 3:用 Bazelisk 自动下载版本

1
2
3
4
wget https://github.com/bazelbuild/bazelisk/releases/download/v1.21.0/bazelisk-linux-amd64
chmod +x bazelisk-linux-amd64
sudo mv bazelisk-linux-amd64 /usr/local/bin/bazel
bazel --version

第一次运行时会自动拉取所需版本。

使用Bazel

命令 作用
bazel build //target 构建指定目标
bazel test //target 运行指定测试
bazel run //target 构建并运行可执行文件
bazel clean 清理构建缓存

项目结构示例

假设你有一个 C++ 项目,目录结构:

1
2
3
4
5
6
WORKSPACE
BUILD
main.cpp
hello.h
hello.cpp
hello_test.cpp
  • WORKSPACE 文件:标记项目根目录,Bazel 必需。内容可以为空。
  • BUILD 文件:描述如何构建项目。

写一个简单 BUILD 文件

BUILDview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cc_library(
name = "hello_lib",
srcs = ["hello.cpp"],
hdrs = ["hello.h"],
)

cc_binary(
name = "hello_bin",
srcs = ["main.cpp"],
deps = [":hello_lib"],
)

cc_test(
name = "hello_test",
srcs = ["hello_test.cpp"],
deps = [":hello_lib", "@googletest//:gtest_main"],
)

简单源码示例

hello.hview raw
1
2
#pragma once
void say_hello();
hello.cppview raw
1
2
3
4
5
6
#include <iostream>
#include "hello.h"

void say_hello() {
std::cout << "Hello, Bazel!" << std::endl;
}
hello_test.cppview raw
1
2
3
4
5
6
7
8
9
10
#include "hello.h"
#include <gtest/gtest.h>

TEST(HelloTest, Basic) {
EXPECT_NO_THROW(say_hello());
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
main.cppview raw
1
2
3
4
5
6
#include "hello.h"

int main() {
say_hello();
return 0;
}

构建和测试

  • 编译可执行文件

    1
    bazel build //:hello_bin

    其中,冒号用于分隔路径和目标。

  • 运行可执行文件

    1
    bazel run //:hello_bin
  • 运行测试

    1
    bazel test //:hello_test

shared_ptr是线程安全的吗?

Boost官网:shared_ptr_thread_safety

shared_ptr与内建类型(比如int, char;std::string不是内建类型)具有相同的线程安全等级:

  • 同一个shared_ptr可以被并发读;
  • 不同的shared_ptr可以被并发写(析构也是写)。
  • 其他并发访问是未定义的。

Examples:

1
shared_ptr<int> p(new int(42));

Code Example 4. Reading a shared_ptr from two threads

1
2
3
4
5
// thread A
shared_ptr<int> p2(p); // reads p

// thread B
shared_ptr<int> p3(p); // OK, multiple reads are safe

读取同一个shared_ptr是线程安全的。
同时增加引用计数,安全。

Code Example 5. Writing different shared_ptr instances from two threads

1
2
3
4
5
// thread A
p.reset(new int(1912)); // writes p

// thread B
p2.reset(); // OK, writes p2

写不同的shared_ptr实例是线程安全的。
不同的实例各自更新自己的引用计数控制块指针,安全。
对共同掌管的资源的引用计数原子减1,安全。

Code Example 6. Reading and writing a shared_ptr from two threads

1
2
3
4
5
// thread A
p = p3; // reads p3, writes p

// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write

同时读写同一个shared_ptr实例,是线程不安全的。
同时对引用计数进行增减,如果先看到减到0,那么可能资源已经被释放。

Code Example 7. Reading and destroying a shared_ptr from two threads

1
2
3
4
5
// thread A
p3 = p2; // reads p2, writes p3

// thread B
// p2 goes out of scope: undefined, the destructor is considered a "write access"

同时读写(析构也是写)同一个shared_ptr实例,是线程不安全的。

Code Example 8. Writing a shared_ptr from two threads

1
2
3
4
5
// thread A
p3.reset(new int(1));

// thread B
p3.reset(new int(2)); // undefined, multiple writes

同时写同一个shared_ptr,可能对引用计数操作多次(应该只能操作一次),线程不安全。

测试:模拟潜在竞态条件:

最后一个引用即将销毁时,另一个线程试图复制

示例1:复制构造和reset()竞争
race1.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>

struct Test {
Test() { std::cout << "Test constructed\n"; }
~Test() { std::cout << "Test destroyed\n"; }
};

void thread_copy(std::shared_ptr<Test>& ptr) {
// 模拟延迟,试图在主线程销毁后复制
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Thread attempting to copy shared_ptr\n";
std::shared_ptr<Test> local_copy = ptr; // 资源可能已经释放
if (local_copy) { // shared_ptr 还存在,所以可以用来检查资源是否有效
std::cout << "Thread copied shared_ptr\n";
} else {
std::cout << "Thread failed to copy shared_ptr\n";
}
}

int main() {
std::shared_ptr<Test> ptr = std::make_shared<Test>();

std::thread t(thread_copy, std::ref(ptr));

// 主线程销毁 shared_ptr
std::this_thread::sleep_for(std::chrono::milliseconds(50));
ptr.reset(); // 引用计数降为 0,销毁对象

t.join();
return 0;
}

总结: reset() 与复制构造需要加锁保护。

示例2:复制构造和析构竞争
race2.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>

struct Test {
Test() { std::cout << "Test constructed\n"; }
~Test() { std::cout << "Test destroyed\n"; }
};

void thread_copy(std::shared_ptr<Test>& ptr) {
// 模拟延迟,试图在主线程销毁后复制
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Thread attempting to copy shared_ptr\n";
std::shared_ptr<Test> local_copy = ptr; // 如果 ptr 已经销毁,这里是未定义行为
if (local_copy) { // 可能“成功”复制一个已经销毁的 shared_ptr
std::cout << "Thread copied shared_ptr\n";
std::cout << "Use count in thread: "
<< local_copy.use_count() << "\n"; // 引用计数控制块是一个野指针
} else {
std::cout << "Thread failed to copy shared_ptr\n";
}
}

int main() {
std::thread t;

{
std::shared_ptr<Test> ptr = std::make_shared<Test>();

t = std::thread(thread_copy, std::ref(ptr));

// 主线程销毁 shared_ptr
std::this_thread::sleep_for(std::chrono::milliseconds(50));

// 析构,引用计数降为 0,销毁对象
}

t.join();
return 0;
}

总结:

  • 不能以左值引用来复制构造shared_ptr,否则会存在竞争。
  • 可以使用const引用,因为可以延续shared_ptr的生命期,析构被推迟,间接消除了竞态。
  • 程序中shared_ptr读写操作同时存在时,需要加锁。
  • 要防止shared_ptr析构:在shared_ptr副本的整个作用域内加锁同样可以保护这种情况。
  • C++20 开始支持 atomic<shared_ptr<T>>,可以安全地在多个线程之间共享和更新 shared_ptr。
  • 如果 thread A 只是想观察 p2 是否还存在,可以使用 std::weak_ptr 来观察。

shared_ptr为什么要隐式自持一个weak count?

每个 shared_ptr 和 weak_ptr 都指向一个 控制块(control block),这个控制块通常包含:

名称 作用
strong count 当前活跃的 shared_ptr 数量
weak count 当前活跃的 weak_ptr 数量 + 当前活跃的 shared_ptr 数量
指向对象的指针 被管理的资源

控制块的生命周期由 weak count 决定,只要还有 weak_ptr 或 shared_ptr 存在,控制块就不能被销毁。

  • weak_ptr和shared_ptr可能存在只有两者之一的情况,所以他们都必须要维护控制块的生命周期。
  • 如果只有weak_ptr对weak count进行计数,那么可能出现shared_ptr和weak_ptr共同看到weak count为0的情况:
    • weak_ptr析构将weak count降低为0,准备释放控制块;
    • shared_ptr析构或reset,检测到weak count为0,准备释放控制块;
    • 这样就释放了两次,因为他们都持有指针,且没有设置相互通知的机制。
  • 但是,如果weak_ptr和shared_ptr都对weak count进行计数,那么就不可能同时观察到weak count为0的情况。

动手实现一个shared_ptr

SimpleSharedPtr
SimpleSharedPtr.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#include <iostream>
#include <atomic>
#include <functional>
#include <stdexcept>

template<typename T>
class SimpleSharedPtr; // 先声明

template<typename T>
class SimpleWeakPtr;

template<typename T>
class ControlBlock {
public:
std::atomic<int> shared_count;
std::atomic<int> weak_count;
T* ptr;
std::function<void(T*)> deleter;

// 每个shared_ptr自持一个weak count
ControlBlock(T* p, std::function<void(T*)> d)
: shared_count(1), weak_count(1), ptr(p), deleter(d ? d : [](T* p){ delete p; }) {}

~ControlBlock() = default;
};

template<typename T>
class SimpleSharedPtr {
private:
ControlBlock<T>* ctrl;

void release() {
if (ctrl) {
// 减shared_count
if (ctrl->shared_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
// 最后一个shared_ptr,释放资源
try {
ctrl->deleter(ctrl->ptr);
} catch (...) {
std::cerr << "Exception in deleter\n";
}
ctrl->ptr = nullptr;

// 再减少weak_count,自己占有一个weak计数,减少它
if (ctrl->weak_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
delete ctrl;
}
}
ctrl = nullptr;
}
}

public:
explicit SimpleSharedPtr(T* p = nullptr, std::function<void(T*)> d = nullptr) {
if (p) {
ctrl = new ControlBlock<T>(p, d);
// shared_count=1, weak_count=0
} else {
ctrl = nullptr;
}
}

// 拷贝构造
SimpleSharedPtr(const SimpleSharedPtr& other) : ctrl(other.ctrl) {
if (ctrl) {
ctrl->shared_count.fetch_add(1, std::memory_order_relaxed);
}
}

// 移动构造
SimpleSharedPtr(SimpleSharedPtr&& other) noexcept : ctrl(other.ctrl) {
other.ctrl = nullptr;
}

// 析构
~SimpleSharedPtr() {
release();
}

// 拷贝赋值
SimpleSharedPtr& operator=(const SimpleSharedPtr& other) {
if (this != &other) {
release();
ctrl = other.ctrl;
if (ctrl) {
ctrl->shared_count.fetch_add(1, std::memory_order_relaxed);
}
}
return *this;
}

// 移动赋值
SimpleSharedPtr& operator=(SimpleSharedPtr&& other) noexcept {
if (this != &other) {
release();
ctrl = other.ctrl;
other.ctrl = nullptr;
}
return *this;
}

T* get() const {
return ctrl ? ctrl->ptr : nullptr;
}

T& operator*() const {
if (!get()) throw std::runtime_error("Dereferencing null pointer");
return *(ctrl->ptr);
}

T* operator->() const {
return get();
}

int use_count() const {
return ctrl ? ctrl->shared_count.load(std::memory_order_relaxed) : 0;
}

bool unique() const {
return use_count() == 1;
}

explicit operator bool() const {
return get() != nullptr;
}

void reset(T* p = nullptr, std::function<void(T*)> d = nullptr) {
release();
if (p) {
ctrl = new ControlBlock<T>(p, d);
} else {
ctrl = nullptr;
}
}

// 给 SimpleWeakPtr 访问 ControlBlock 指针权限
friend class SimpleWeakPtr<T>;

private:
// SimpleSharedPtr增加一个私有构造,能从控制块构造shared_ptr(配合weak_ptr的lock)
SimpleSharedPtr(ControlBlock<T>* c) : ctrl(c) {}
};

template<typename T>
class SimpleWeakPtr {
private:
ControlBlock<T>* ctrl;

void release() {
if (ctrl) {
if (ctrl->weak_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
// 只有弱引用且没有shared_ptr存在时,销毁控制块
if (ctrl->shared_count.load(std::memory_order_acquire) == 0) {
delete ctrl;
}
}
ctrl = nullptr;
}
}

public:
SimpleWeakPtr() : ctrl(nullptr) {}

// 从 shared_ptr 构造 weak_ptr
SimpleWeakPtr(const SimpleSharedPtr<T>& shared) : ctrl(shared.ctrl) {
if (ctrl) {
ctrl->weak_count.fetch_add(1, std::memory_order_relaxed);
}
}

// 拷贝构造
SimpleWeakPtr(const SimpleWeakPtr& other) : ctrl(other.ctrl) {
if (ctrl) {
ctrl->weak_count.fetch_add(1, std::memory_order_relaxed);
}
}

// 移动构造
SimpleWeakPtr(SimpleWeakPtr&& other) noexcept : ctrl(other.ctrl) {
other.ctrl = nullptr;
}

~SimpleWeakPtr() {
release();
}

// 拷贝赋值
SimpleWeakPtr& operator=(const SimpleWeakPtr& other) {
if (this != &other) {
release();
ctrl = other.ctrl;
if (ctrl) {
ctrl->weak_count.fetch_add(1, std::memory_order_relaxed);
}
}
return *this;
}

// 移动赋值
SimpleWeakPtr& operator=(SimpleWeakPtr&& other) noexcept {
if (this != &other) {
release();
ctrl = other.ctrl;
other.ctrl = nullptr;
}
return *this;
}

int use_count() const {
return ctrl ? ctrl->shared_count.load(std::memory_order_relaxed) : 0;
}

bool expired() const {
return use_count() == 0;
}

// 尝试获取shared_ptr,资源已被销毁则返回空shared_ptr
SimpleSharedPtr<T> lock() const {
if (expired()) {
return SimpleSharedPtr<T>();
} else {
// 尝试增加shared_count
int old_count = ctrl->shared_count.load(std::memory_order_relaxed);
while (old_count != 0) {
if (ctrl->shared_count.compare_exchange_weak(old_count, old_count + 1,
std::memory_order_acq_rel, std::memory_order_relaxed)) {
// 成功增加shared_count
return SimpleSharedPtr<T>(ctrl);
}
// old_count 已被更新,继续循环
}
return SimpleSharedPtr<T>();
}
}

private:
// 让 SimpleSharedPtr 可以通过控制块构造 shared_ptr
friend class SimpleSharedPtr<T>;

explicit SimpleWeakPtr(ControlBlock<T>* c) : ctrl(c) {}
};


int main() {
SimpleSharedPtr<int> sp1(new int(42));
SimpleWeakPtr<int> wp1 = sp1;

std::cout << "use_count: " << sp1.use_count() << "\n"; // 1
std::cout << "expired: " << wp1.expired() << "\n"; // 0

if (auto sp2 = wp1.lock()) {
std::cout << "locked value: " << *sp2 << "\n"; // 42
std::cout << "use_count after lock: " << sp2.use_count() << "\n"; // 2
}

sp1.reset();

std::cout << "expired after reset: " << wp1.expired() << "\n"; // 1

if (auto sp3 = wp1.lock()) {
std::cout << "Should not print\n";
} else {
std::cout << "lock failed, resource expired\n";
}

return 0;
}

附录:shared_ptr源码

  • /usr/include/c++/11/bits/shared_ptr.h
  • /usr/include/c++/11/bits/shared_ptr_base.h
  • /usr/include/c++/11/bits/shared_ptr_atomic.h
shared_ptr.h
shared_ptr.hview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
// shared_ptr and weak_ptr implementation -*- C++ -*-

// Copyright (C) 2007-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.

// GCC Note: Based on files from version 1.32.0 of the Boost library.

// shared_count.hpp
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.

// shared_ptr.hpp
// Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
// Copyright (C) 2001, 2002, 2003 Peter Dimov

// weak_ptr.hpp
// Copyright (C) 2001, 2002, 2003 Peter Dimov

// enable_shared_from_this.hpp
// Copyright (C) 2002 Peter Dimov

// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

/** @file
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{memory}
*/

#ifndef _SHARED_PTR_H
#define _SHARED_PTR_H 1

#include <iosfwd> // std::basic_ostream
#include <bits/shared_ptr_base.h>

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

/**
* @addtogroup pointer_abstractions
* @{
*/

// 20.7.2.2.11 shared_ptr I/O

/// Write the stored pointer to an ostream.
/// @relates shared_ptr
template<typename _Ch, typename _Tr, typename _Tp, _Lock_policy _Lp>
inline std::basic_ostream<_Ch, _Tr>&
operator<<(std::basic_ostream<_Ch, _Tr>& __os,
const __shared_ptr<_Tp, _Lp>& __p)
{
__os << __p.get();
return __os;
}

template<typename _Del, typename _Tp, _Lock_policy _Lp>
inline _Del*
get_deleter(const __shared_ptr<_Tp, _Lp>& __p) noexcept
{
#if __cpp_rtti
return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del)));
#else
return 0;
#endif
}

/// 20.7.2.2.10 shared_ptr get_deleter

/// If `__p` has a deleter of type `_Del`, return a pointer to it.
/// @relates shared_ptr
template<typename _Del, typename _Tp>
inline _Del*
get_deleter(const shared_ptr<_Tp>& __p) noexcept
{
#if __cpp_rtti
return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del)));
#else
return 0;
#endif
}

/**
* @brief A smart pointer with reference-counted copy semantics.
*
* A `shared_ptr` object is either empty or _owns_ a pointer passed
* to the constructor. Copies of a `shared_ptr` share ownership of
* the same pointer. When the last `shared_ptr` that owns the pointer
* is destroyed or reset, the owned pointer is freed (either by `delete`
* or by invoking a custom deleter that was passed to the constructor).
*
* A `shared_ptr` also stores another pointer, which is usually
* (but not always) the same pointer as it owns. The stored pointer
* can be retrieved by calling the `get()` member function.
*
* The equality and relational operators for `shared_ptr` only compare
* the stored pointer returned by `get()`, not the owned pointer.
* To test whether two `shared_ptr` objects share ownership of the same
* pointer see `std::shared_ptr::owner_before` and `std::owner_less`.
*/
template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>
{
template<typename... _Args>
using _Constructible = typename enable_if<
is_constructible<__shared_ptr<_Tp>, _Args...>::value
>::type;

template<typename _Arg>
using _Assignable = typename enable_if<
is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr&
>::type;

public:

/// The type pointed to by the stored pointer, remove_extent_t<_Tp>
using element_type = typename __shared_ptr<_Tp>::element_type;

#if __cplusplus >= 201703L
# define __cpp_lib_shared_ptr_weak_type 201606
/// The corresponding weak_ptr type for this shared_ptr
using weak_type = weak_ptr<_Tp>;
#endif
/**
* @brief Construct an empty %shared_ptr.
* @post use_count()==0 && get()==0
*/
constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { }

shared_ptr(const shared_ptr&) noexcept = default; ///< Copy constructor

/**
* @brief Construct a %shared_ptr that owns the pointer @a __p.
* @param __p A pointer that is convertible to element_type*.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @c delete @a __p is called.
*/
template<typename _Yp, typename = _Constructible<_Yp*>>
explicit
shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }

/**
* @brief Construct a %shared_ptr that owns the pointer @a __p
* and the deleter @a __d.
* @param __p A pointer.
* @param __d A deleter.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @a __d(__p) is called.
*
* Requirements: _Deleter's copy constructor and destructor must
* not throw
*
* __shared_ptr will release __p by calling __d(__p)
*/
template<typename _Yp, typename _Deleter,
typename = _Constructible<_Yp*, _Deleter>>
shared_ptr(_Yp* __p, _Deleter __d)
: __shared_ptr<_Tp>(__p, std::move(__d)) { }

/**
* @brief Construct a %shared_ptr that owns a null pointer
* and the deleter @a __d.
* @param __p A null pointer constant.
* @param __d A deleter.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @a __d(__p) is called.
*
* Requirements: _Deleter's copy constructor and destructor must
* not throw
*
* The last owner will call __d(__p)
*/
template<typename _Deleter>
shared_ptr(nullptr_t __p, _Deleter __d)
: __shared_ptr<_Tp>(__p, std::move(__d)) { }

/**
* @brief Construct a %shared_ptr that owns the pointer @a __p
* and the deleter @a __d.
* @param __p A pointer.
* @param __d A deleter.
* @param __a An allocator.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @a __d(__p) is called.
*
* Requirements: _Deleter's copy constructor and destructor must
* not throw _Alloc's copy constructor and destructor must not
* throw.
*
* __shared_ptr will release __p by calling __d(__p)
*/
template<typename _Yp, typename _Deleter, typename _Alloc,
typename = _Constructible<_Yp*, _Deleter, _Alloc>>
shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
: __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }

/**
* @brief Construct a %shared_ptr that owns a null pointer
* and the deleter @a __d.
* @param __p A null pointer constant.
* @param __d A deleter.
* @param __a An allocator.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @a __d(__p) is called.
*
* Requirements: _Deleter's copy constructor and destructor must
* not throw _Alloc's copy constructor and destructor must not
* throw.
*
* The last owner will call __d(__p)
*/
template<typename _Deleter, typename _Alloc>
shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
: __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }

// Aliasing constructor

/**
* @brief Constructs a `shared_ptr` instance that stores `__p`
* and shares ownership with `__r`.
* @param __r A `shared_ptr`.
* @param __p A pointer that will remain valid while `*__r` is valid.
* @post `get() == __p && use_count() == __r.use_count()`
*
* This can be used to construct a `shared_ptr` to a sub-object
* of an object managed by an existing `shared_ptr`. The complete
* object will remain valid while any `shared_ptr` owns it, even
* if they don't store a pointer to the complete object.
*
* @code
* shared_ptr<pair<int,int>> pii(new pair<int,int>());
* shared_ptr<int> pi(pii, &pii->first);
* assert(pii.use_count() == 2);
* @endcode
*/
template<typename _Yp>
shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept
: __shared_ptr<_Tp>(__r, __p) { }

#if __cplusplus > 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2996. Missing rvalue overloads for shared_ptr operations
/**
* @brief Constructs a `shared_ptr` instance that stores `__p`
* and shares ownership with `__r`.
* @param __r A `shared_ptr`.
* @param __p A pointer that will remain valid while `*__r` is valid.
* @post `get() == __p && !__r.use_count() && !__r.get()`
*
* This can be used to construct a `shared_ptr` to a sub-object
* of an object managed by an existing `shared_ptr`. The complete
* object will remain valid while any `shared_ptr` owns it, even
* if they don't store a pointer to the complete object.
*
* @code
* shared_ptr<pair<int,int>> pii(new pair<int,int>());
* shared_ptr<int> pi1(pii, &pii->first);
* assert(pii.use_count() == 2);
* shared_ptr<int> pi2(std::move(pii), &pii->second);
* assert(pii.use_count() == 0);
* @endcode
*/
template<typename _Yp>
shared_ptr(shared_ptr<_Yp>&& __r, element_type* __p) noexcept
: __shared_ptr<_Tp>(std::move(__r), __p) { }
#endif
/**
* @brief If @a __r is empty, constructs an empty %shared_ptr;
* otherwise construct a %shared_ptr that shares ownership
* with @a __r.
* @param __r A %shared_ptr.
* @post get() == __r.get() && use_count() == __r.use_count()
*/
template<typename _Yp,
typename = _Constructible<const shared_ptr<_Yp>&>>
shared_ptr(const shared_ptr<_Yp>& __r) noexcept
: __shared_ptr<_Tp>(__r) { }

/**
* @brief Move-constructs a %shared_ptr instance from @a __r.
* @param __r A %shared_ptr rvalue.
* @post *this contains the old value of @a __r, @a __r is empty.
*/
shared_ptr(shared_ptr&& __r) noexcept
: __shared_ptr<_Tp>(std::move(__r)) { }

/**
* @brief Move-constructs a %shared_ptr instance from @a __r.
* @param __r A %shared_ptr rvalue.
* @post *this contains the old value of @a __r, @a __r is empty.
*/
template<typename _Yp, typename = _Constructible<shared_ptr<_Yp>>>
shared_ptr(shared_ptr<_Yp>&& __r) noexcept
: __shared_ptr<_Tp>(std::move(__r)) { }

/**
* @brief Constructs a %shared_ptr that shares ownership with @a __r
* and stores a copy of the pointer stored in @a __r.
* @param __r A weak_ptr.
* @post use_count() == __r.use_count()
* @throw bad_weak_ptr when __r.expired(),
* in which case the constructor has no effect.
*/
template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
explicit shared_ptr(const weak_ptr<_Yp>& __r)
: __shared_ptr<_Tp>(__r) { }

#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
template<typename _Yp, typename = _Constructible<auto_ptr<_Yp>>>
shared_ptr(auto_ptr<_Yp>&& __r);
#pragma GCC diagnostic pop
#endif

// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2399. shared_ptr's constructor from unique_ptr should be constrained
template<typename _Yp, typename _Del,
typename = _Constructible<unique_ptr<_Yp, _Del>>>
shared_ptr(unique_ptr<_Yp, _Del>&& __r)
: __shared_ptr<_Tp>(std::move(__r)) { }

#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED
// This non-standard constructor exists to support conversions that
// were possible in C++11 and C++14 but are ill-formed in C++17.
// If an exception is thrown this constructor has no effect.
template<typename _Yp, typename _Del,
_Constructible<unique_ptr<_Yp, _Del>, __sp_array_delete>* = 0>
shared_ptr(unique_ptr<_Yp, _Del>&& __r)
: __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { }
#endif

/**
* @brief Construct an empty %shared_ptr.
* @post use_count() == 0 && get() == nullptr
*/
constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }

shared_ptr& operator=(const shared_ptr&) noexcept = default;

template<typename _Yp>
_Assignable<const shared_ptr<_Yp>&>
operator=(const shared_ptr<_Yp>& __r) noexcept
{
this->__shared_ptr<_Tp>::operator=(__r);
return *this;
}

#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
template<typename _Yp>
_Assignable<auto_ptr<_Yp>>
operator=(auto_ptr<_Yp>&& __r)
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}
#pragma GCC diagnostic pop
#endif

shared_ptr&
operator=(shared_ptr&& __r) noexcept
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}

template<class _Yp>
_Assignable<shared_ptr<_Yp>>
operator=(shared_ptr<_Yp>&& __r) noexcept
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}

template<typename _Yp, typename _Del>
_Assignable<unique_ptr<_Yp, _Del>>
operator=(unique_ptr<_Yp, _Del>&& __r)
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}

private:
// This constructor is non-standard, it is used by allocate_shared.
template<typename _Alloc, typename... _Args>
shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args)
: __shared_ptr<_Tp>(__tag, std::forward<_Args>(__args)...)
{ }

template<typename _Yp, typename _Alloc, typename... _Args>
friend shared_ptr<_Yp>
allocate_shared(const _Alloc& __a, _Args&&... __args);

// This constructor is non-standard, it is used by weak_ptr::lock().
shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t) noexcept
: __shared_ptr<_Tp>(__r, std::nothrow) { }

friend class weak_ptr<_Tp>;
};

#if __cpp_deduction_guides >= 201606
template<typename _Tp>
shared_ptr(weak_ptr<_Tp>) -> shared_ptr<_Tp>;
template<typename _Tp, typename _Del>
shared_ptr(unique_ptr<_Tp, _Del>) -> shared_ptr<_Tp>;
#endif

// 20.7.2.2.7 shared_ptr comparisons

/// @relates shared_ptr @{

/// Equality operator for shared_ptr objects, compares the stored pointers
template<typename _Tp, typename _Up>
_GLIBCXX_NODISCARD inline bool
operator==(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return __a.get() == __b.get(); }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator==(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
{ return !__a; }

#ifdef __cpp_lib_three_way_comparison
template<typename _Tp, typename _Up>
inline strong_ordering
operator<=>(const shared_ptr<_Tp>& __a,
const shared_ptr<_Up>& __b) noexcept
{ return compare_three_way()(__a.get(), __b.get()); }

template<typename _Tp>
inline strong_ordering
operator<=>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
{
using pointer = typename shared_ptr<_Tp>::element_type*;
return compare_three_way()(__a.get(), static_cast<pointer>(nullptr));
}
#else
/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator==(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{ return !__a; }

/// Inequality operator for shared_ptr objects, compares the stored pointers
template<typename _Tp, typename _Up>
_GLIBCXX_NODISCARD inline bool
operator!=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return __a.get() != __b.get(); }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator!=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
{ return (bool)__a; }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator!=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{ return (bool)__a; }

/// Relational operator for shared_ptr objects, compares the stored pointers
template<typename _Tp, typename _Up>
_GLIBCXX_NODISCARD inline bool
operator<(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{
using _Tp_elt = typename shared_ptr<_Tp>::element_type;
using _Up_elt = typename shared_ptr<_Up>::element_type;
using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type;
return less<_Vp>()(__a.get(), __b.get());
}

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator<(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
{
using _Tp_elt = typename shared_ptr<_Tp>::element_type;
return less<_Tp_elt*>()(__a.get(), nullptr);
}

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator<(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{
using _Tp_elt = typename shared_ptr<_Tp>::element_type;
return less<_Tp_elt*>()(nullptr, __a.get());
}

/// Relational operator for shared_ptr objects, compares the stored pointers
template<typename _Tp, typename _Up>
_GLIBCXX_NODISCARD inline bool
operator<=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return !(__b < __a); }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator<=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
{ return !(nullptr < __a); }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator<=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{ return !(__a < nullptr); }

/// Relational operator for shared_ptr objects, compares the stored pointers
template<typename _Tp, typename _Up>
_GLIBCXX_NODISCARD inline bool
operator>(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return (__b < __a); }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
{ return nullptr < __a; }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator>(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{ return __a < nullptr; }

/// Relational operator for shared_ptr objects, compares the stored pointers
template<typename _Tp, typename _Up>
_GLIBCXX_NODISCARD inline bool
operator>=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return !(__a < __b); }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator>=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
{ return !(__a < nullptr); }

/// shared_ptr comparison with nullptr
template<typename _Tp>
_GLIBCXX_NODISCARD inline bool
operator>=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{ return !(nullptr < __a); }
#endif

// 20.7.2.2.8 shared_ptr specialized algorithms.

/// Swap overload for shared_ptr
template<typename _Tp>
inline void
swap(shared_ptr<_Tp>& __a, shared_ptr<_Tp>& __b) noexcept
{ __a.swap(__b); }

// 20.7.2.2.9 shared_ptr casts.

/// Convert type of `shared_ptr`, via `static_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
static_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
}

/// Convert type of `shared_ptr`, via `const_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
const_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
}

/// Convert type of `shared_ptr`, via `dynamic_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
return _Sp(__r, __p);
return _Sp();
}

#if __cplusplus >= 201703L
/// Convert type of `shared_ptr`, via `reinterpret_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
}

#if __cplusplus > 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2996. Missing rvalue overloads for shared_ptr operations

/// Convert type of `shared_ptr` rvalue, via `static_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
static_pointer_cast(shared_ptr<_Up>&& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(std::move(__r),
static_cast<typename _Sp::element_type*>(__r.get()));
}

/// Convert type of `shared_ptr` rvalue, via `const_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
const_pointer_cast(shared_ptr<_Up>&& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(std::move(__r),
const_cast<typename _Sp::element_type*>(__r.get()));
}

/// Convert type of `shared_ptr` rvalue, via `dynamic_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
return _Sp(std::move(__r), __p);
return _Sp();
}

/// Convert type of `shared_ptr` rvalue, via `reinterpret_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(std::move(__r),
reinterpret_cast<typename _Sp::element_type*>(__r.get()));
}
#endif // C++20
#endif // C++17

/// @}

/**
* @brief A non-owning observer for a pointer owned by a shared_ptr
*
* A weak_ptr provides a safe alternative to a raw pointer when you want
* a non-owning reference to an object that is managed by a shared_ptr.
*
* Unlike a raw pointer, a weak_ptr can be converted to a new shared_ptr
* that shares ownership with every other shared_ptr that already owns
* the pointer. In other words you can upgrade from a non-owning "weak"
* reference to an owning shared_ptr, without having access to any of
* the existing shared_ptr objects.
*
* Also unlike a raw pointer, a weak_ptr does not become "dangling" after
* the object it points to has been destroyed. Instead, a weak_ptr
* becomes _expired_ and can no longer be converted to a shared_ptr that
* owns the freed pointer, so you cannot accidentally access the pointed-to
* object after it has been destroyed.
*/
template<typename _Tp>
class weak_ptr : public __weak_ptr<_Tp>
{
template<typename _Arg>
using _Constructible = typename enable_if<
is_constructible<__weak_ptr<_Tp>, _Arg>::value
>::type;

template<typename _Arg>
using _Assignable = typename enable_if<
is_assignable<__weak_ptr<_Tp>&, _Arg>::value, weak_ptr&
>::type;

public:
constexpr weak_ptr() noexcept = default;

template<typename _Yp,
typename = _Constructible<const shared_ptr<_Yp>&>>
weak_ptr(const shared_ptr<_Yp>& __r) noexcept
: __weak_ptr<_Tp>(__r) { }

weak_ptr(const weak_ptr&) noexcept = default;

template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
weak_ptr(const weak_ptr<_Yp>& __r) noexcept
: __weak_ptr<_Tp>(__r) { }

weak_ptr(weak_ptr&&) noexcept = default;

template<typename _Yp, typename = _Constructible<weak_ptr<_Yp>>>
weak_ptr(weak_ptr<_Yp>&& __r) noexcept
: __weak_ptr<_Tp>(std::move(__r)) { }

weak_ptr&
operator=(const weak_ptr& __r) noexcept = default;

template<typename _Yp>
_Assignable<const weak_ptr<_Yp>&>
operator=(const weak_ptr<_Yp>& __r) noexcept
{
this->__weak_ptr<_Tp>::operator=(__r);
return *this;
}

template<typename _Yp>
_Assignable<const shared_ptr<_Yp>&>
operator=(const shared_ptr<_Yp>& __r) noexcept
{
this->__weak_ptr<_Tp>::operator=(__r);
return *this;
}

weak_ptr&
operator=(weak_ptr&& __r) noexcept = default;

template<typename _Yp>
_Assignable<weak_ptr<_Yp>>
operator=(weak_ptr<_Yp>&& __r) noexcept
{
this->__weak_ptr<_Tp>::operator=(std::move(__r));
return *this;
}

shared_ptr<_Tp>
lock() const noexcept
{ return shared_ptr<_Tp>(*this, std::nothrow); }
};

#if __cpp_deduction_guides >= 201606
template<typename _Tp>
weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>;
#endif

// 20.7.2.3.6 weak_ptr specialized algorithms.
/// Swap overload for weak_ptr
/// @relates weak_ptr
template<typename _Tp>
inline void
swap(weak_ptr<_Tp>& __a, weak_ptr<_Tp>& __b) noexcept
{ __a.swap(__b); }


/// Primary template owner_less
template<typename _Tp = void>
struct owner_less;

/// Void specialization of owner_less compares either shared_ptr or weak_ptr
template<>
struct owner_less<void> : _Sp_owner_less<void, void>
{ };

/// Partial specialization of owner_less for shared_ptr.
template<typename _Tp>
struct owner_less<shared_ptr<_Tp>>
: public _Sp_owner_less<shared_ptr<_Tp>, weak_ptr<_Tp>>
{ };

/// Partial specialization of owner_less for weak_ptr.
template<typename _Tp>
struct owner_less<weak_ptr<_Tp>>
: public _Sp_owner_less<weak_ptr<_Tp>, shared_ptr<_Tp>>
{ };

/**
* @brief Base class allowing use of member function shared_from_this.
*/
template<typename _Tp>
class enable_shared_from_this
{
protected:
constexpr enable_shared_from_this() noexcept { }

enable_shared_from_this(const enable_shared_from_this&) noexcept { }

enable_shared_from_this&
operator=(const enable_shared_from_this&) noexcept
{ return *this; }

~enable_shared_from_this() { }

public:
shared_ptr<_Tp>
shared_from_this()
{ return shared_ptr<_Tp>(this->_M_weak_this); }

shared_ptr<const _Tp>
shared_from_this() const
{ return shared_ptr<const _Tp>(this->_M_weak_this); }

#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
#define __cpp_lib_enable_shared_from_this 201603
weak_ptr<_Tp>
weak_from_this() noexcept
{ return this->_M_weak_this; }

weak_ptr<const _Tp>
weak_from_this() const noexcept
{ return this->_M_weak_this; }
#endif

private:
template<typename _Tp1>
void
_M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept
{ _M_weak_this._M_assign(__p, __n); }

// Found by ADL when this is an associated class.
friend const enable_shared_from_this*
__enable_shared_from_this_base(const __shared_count<>&,
const enable_shared_from_this* __p)
{ return __p; }

template<typename, _Lock_policy>
friend class __shared_ptr;

mutable weak_ptr<_Tp> _M_weak_this;
};

/// @relates shared_ptr @{

/**
* @brief Create an object that is owned by a shared_ptr.
* @param __a An allocator.
* @param __args Arguments for the @a _Tp object's constructor.
* @return A shared_ptr that owns the newly created object.
* @throw An exception thrown from @a _Alloc::allocate or from the
* constructor of @a _Tp.
*
* A copy of @a __a will be used to allocate memory for the shared_ptr
* and the new object.
*/
template<typename _Tp, typename _Alloc, typename... _Args>
inline shared_ptr<_Tp>
allocate_shared(const _Alloc& __a, _Args&&... __args)
{
static_assert(!is_array<_Tp>::value, "make_shared<T[]> not supported");

return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a},
std::forward<_Args>(__args)...);
}

/**
* @brief Create an object that is owned by a shared_ptr.
* @param __args Arguments for the @a _Tp object's constructor.
* @return A shared_ptr that owns the newly created object.
* @throw std::bad_alloc, or an exception thrown from the
* constructor of @a _Tp.
*/
template<typename _Tp, typename... _Args>
inline shared_ptr<_Tp>
make_shared(_Args&&... __args)
{
typedef typename std::remove_cv<_Tp>::type _Tp_nc;
return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
std::forward<_Args>(__args)...);
}

/// std::hash specialization for shared_ptr.
template<typename _Tp>
struct hash<shared_ptr<_Tp>>
: public __hash_base<size_t, shared_ptr<_Tp>>
{
size_t
operator()(const shared_ptr<_Tp>& __s) const noexcept
{
return std::hash<typename shared_ptr<_Tp>::element_type*>()(__s.get());
}
};

/// @} relates shared_ptr
/// @} group pointer_abstractions

#if __cplusplus >= 201703L
namespace __detail::__variant
{
template<typename> struct _Never_valueless_alt; // see <variant>

// Provide the strong exception-safety guarantee when emplacing a
// shared_ptr into a variant.
template<typename _Tp>
struct _Never_valueless_alt<std::shared_ptr<_Tp>>
: std::true_type
{ };

// Provide the strong exception-safety guarantee when emplacing a
// weak_ptr into a variant.
template<typename _Tp>
struct _Never_valueless_alt<std::weak_ptr<_Tp>>
: std::true_type
{ };
} // namespace __detail::__variant
#endif // C++17

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

#endif // _SHARED_PTR_H
shared_ptr_base.h
shared_ptr_base.hview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
// shared_ptr and weak_ptr implementation details -*- C++ -*-

// Copyright (C) 2007-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.

// GCC Note: Based on files from version 1.32.0 of the Boost library.

// shared_count.hpp
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.

// shared_ptr.hpp
// Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
// Copyright (C) 2001, 2002, 2003 Peter Dimov

// weak_ptr.hpp
// Copyright (C) 2001, 2002, 2003 Peter Dimov

// enable_shared_from_this.hpp
// Copyright (C) 2002 Peter Dimov

// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

/** @file bits/shared_ptr_base.h
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{memory}
*/

#ifndef _SHARED_PTR_BASE_H
#define _SHARED_PTR_BASE_H 1

#include <typeinfo>
#include <bits/allocated_ptr.h>
#include <bits/allocator.h>
#include <bits/exception_defines.h>
#include <bits/functional_hash.h>
#include <bits/refwrap.h>
#include <bits/stl_function.h> // std::less
#include <bits/unique_ptr.h>
#include <ext/aligned_buffer.h>
#include <ext/atomicity.h>
#include <ext/concurrence.h>
#if __cplusplus > 201703L
# include <compare>
#endif

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
template<typename> class auto_ptr;
#pragma GCC diagnostic pop
#endif

/**
* @brief Exception possibly thrown by @c shared_ptr.
* @ingroup exceptions
*/
class bad_weak_ptr : public std::exception
{
public:
virtual char const* what() const noexcept;

virtual ~bad_weak_ptr() noexcept;
};

// Substitute for bad_weak_ptr object in the case of -fno-exceptions.
inline void
__throw_bad_weak_ptr()
{ _GLIBCXX_THROW_OR_ABORT(bad_weak_ptr()); }

using __gnu_cxx::_Lock_policy;
using __gnu_cxx::__default_lock_policy;
using __gnu_cxx::_S_single;
using __gnu_cxx::_S_mutex;
using __gnu_cxx::_S_atomic;

// Empty helper class except when the template argument is _S_mutex.
template<_Lock_policy _Lp>
class _Mutex_base
{
protected:
// The atomic policy uses fully-fenced builtins, single doesn't care.
enum { _S_need_barriers = 0 };
};

template<>
class _Mutex_base<_S_mutex>
: public __gnu_cxx::__mutex
{
protected:
// This policy is used when atomic builtins are not available.
// The replacement atomic operations might not have the necessary
// memory barriers.
enum { _S_need_barriers = 1 };
};

template<_Lock_policy _Lp = __default_lock_policy>
class _Sp_counted_base
: public _Mutex_base<_Lp>
{
public:
_Sp_counted_base() noexcept
: _M_use_count(1), _M_weak_count(1) { }

virtual
~_Sp_counted_base() noexcept
{ }

// Called when _M_use_count drops to zero, to release the resources
// managed by *this.
virtual void
_M_dispose() noexcept = 0;

// Called when _M_weak_count drops to zero.
virtual void
_M_destroy() noexcept
{ delete this; }

virtual void*
_M_get_deleter(const std::type_info&) noexcept = 0;

void
_M_add_ref_copy()
{ __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }

void
_M_add_ref_lock()
{
if (!_M_add_ref_lock_nothrow())
__throw_bad_weak_ptr();
}

bool
_M_add_ref_lock_nothrow() noexcept;

void
_M_release() noexcept
{
// Be race-detector-friendly. For more info see bits/c++config.
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
_M_dispose();
// There must be a memory barrier between dispose() and destroy()
// to ensure that the effects of dispose() are observed in the
// thread that runs destroy().
// See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
if (_Mutex_base<_Lp>::_S_need_barriers)
{
__atomic_thread_fence (__ATOMIC_ACQ_REL);
}

// Be race-detector-friendly. For more info see bits/c++config.
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
-1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
_M_destroy();
}
}
}

void
_M_weak_add_ref() noexcept
{ __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }

void
_M_weak_release() noexcept
{
// Be race-detector-friendly. For more info see bits/c++config.
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
if (_Mutex_base<_Lp>::_S_need_barriers)
{
// See _M_release(),
// destroy() must observe results of dispose()
__atomic_thread_fence (__ATOMIC_ACQ_REL);
}
_M_destroy();
}
}

long
_M_get_use_count() const noexcept
{
// No memory barrier is used here so there is no synchronization
// with other threads.
return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED);
}

private:
_Sp_counted_base(_Sp_counted_base const&) = delete;
_Sp_counted_base& operator=(_Sp_counted_base const&) = delete;

_Atomic_word _M_use_count; // #shared
_Atomic_word _M_weak_count; // #weak + (#shared != 0)
};

template<>
inline bool
_Sp_counted_base<_S_single>::
_M_add_ref_lock_nothrow() noexcept
{
if (_M_use_count == 0)
return false;
++_M_use_count;
return true;
}

template<>
inline bool
_Sp_counted_base<_S_mutex>::
_M_add_ref_lock_nothrow() noexcept
{
__gnu_cxx::__scoped_lock sentry(*this);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
{
_M_use_count = 0;
return false;
}
return true;
}

template<>
inline bool
_Sp_counted_base<_S_atomic>::
_M_add_ref_lock_nothrow() noexcept
{
// Perform lock-free add-if-not-zero operation.
_Atomic_word __count = _M_get_use_count();
do
{
if (__count == 0)
return false;
// Replace the current counter value with the old value + 1, as
// long as it's not changed meanwhile.
}
while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
true, __ATOMIC_ACQ_REL,
__ATOMIC_RELAXED));
return true;
}

template<>
inline void
_Sp_counted_base<_S_single>::_M_add_ref_copy()
{ ++_M_use_count; }

template<>
inline void
_Sp_counted_base<_S_single>::_M_release() noexcept
{
if (--_M_use_count == 0)
{
_M_dispose();
if (--_M_weak_count == 0)
_M_destroy();
}
}

template<>
inline void
_Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept
{ ++_M_weak_count; }

template<>
inline void
_Sp_counted_base<_S_single>::_M_weak_release() noexcept
{
if (--_M_weak_count == 0)
_M_destroy();
}

template<>
inline long
_Sp_counted_base<_S_single>::_M_get_use_count() const noexcept
{ return _M_use_count; }


// Forward declarations.
template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
class __shared_ptr;

template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
class __weak_ptr;

template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
class __enable_shared_from_this;

template<typename _Tp>
class shared_ptr;

template<typename _Tp>
class weak_ptr;

template<typename _Tp>
struct owner_less;

template<typename _Tp>
class enable_shared_from_this;

template<_Lock_policy _Lp = __default_lock_policy>
class __weak_count;

template<_Lock_policy _Lp = __default_lock_policy>
class __shared_count;


// Counted ptr with no deleter or allocator support
template<typename _Ptr, _Lock_policy _Lp>
class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>
{
public:
explicit
_Sp_counted_ptr(_Ptr __p) noexcept
: _M_ptr(__p) { }

virtual void
_M_dispose() noexcept
{ delete _M_ptr; }

virtual void
_M_destroy() noexcept
{ delete this; }

virtual void*
_M_get_deleter(const std::type_info&) noexcept
{ return nullptr; }

_Sp_counted_ptr(const _Sp_counted_ptr&) = delete;
_Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete;

private:
_Ptr _M_ptr;
};

template<>
inline void
_Sp_counted_ptr<nullptr_t, _S_single>::_M_dispose() noexcept { }

template<>
inline void
_Sp_counted_ptr<nullptr_t, _S_mutex>::_M_dispose() noexcept { }

template<>
inline void
_Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }

template<int _Nm, typename _Tp,
bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
struct _Sp_ebo_helper;

/// Specialization using EBO.
template<int _Nm, typename _Tp>
struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp
{
explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }
explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { }

static _Tp&
_S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); }
};

/// Specialization not using EBO.
template<int _Nm, typename _Tp>
struct _Sp_ebo_helper<_Nm, _Tp, false>
{
explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }
explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { }

static _Tp&
_S_get(_Sp_ebo_helper& __eboh)
{ return __eboh._M_tp; }

private:
_Tp _M_tp;
};

// Support for custom deleter and/or allocator
template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>
{
class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc>
{
typedef _Sp_ebo_helper<0, _Deleter> _Del_base;
typedef _Sp_ebo_helper<1, _Alloc> _Alloc_base;

public:
_Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
: _Del_base(std::move(__d)), _Alloc_base(__a), _M_ptr(__p)
{ }

_Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }
_Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); }

_Ptr _M_ptr;
};

public:
using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>;

// __d(__p) must not throw.
_Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept
: _M_impl(__p, std::move(__d), _Alloc()) { }

// __d(__p) must not throw.
_Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
: _M_impl(__p, std::move(__d), __a) { }

~_Sp_counted_deleter() noexcept { }

virtual void
_M_dispose() noexcept
{ _M_impl._M_del()(_M_impl._M_ptr); }

virtual void
_M_destroy() noexcept
{
__allocator_type __a(_M_impl._M_alloc());
__allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
this->~_Sp_counted_deleter();
}

virtual void*
_M_get_deleter(const type_info& __ti [[__gnu__::__unused__]]) noexcept
{
#if __cpp_rtti
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2400. shared_ptr's get_deleter() should use addressof()
return __ti == typeid(_Deleter)
? std::__addressof(_M_impl._M_del())
: nullptr;
#else
return nullptr;
#endif
}

private:
_Impl _M_impl;
};

// helpers for make_shared / allocate_shared

struct _Sp_make_shared_tag
{
private:
template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
friend class _Sp_counted_ptr_inplace;

static const type_info&
_S_ti() noexcept _GLIBCXX_VISIBILITY(default)
{
alignas(type_info) static constexpr char __tag[sizeof(type_info)] = { };
return reinterpret_cast<const type_info&>(__tag);
}

static bool _S_eq(const type_info&) noexcept;
};

template<typename _Alloc>
struct _Sp_alloc_shared_tag
{
const _Alloc& _M_a;
};

template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
{
class _Impl : _Sp_ebo_helper<0, _Alloc>
{
typedef _Sp_ebo_helper<0, _Alloc> _A_base;

public:
explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { }

_Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }

__gnu_cxx::__aligned_buffer<_Tp> _M_storage;
};

public:
using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>;

// Alloc parameter is not a reference so doesn't alias anything in __args
template<typename... _Args>
_Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args)
: _M_impl(__a)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2070. allocate_shared should use allocator_traits<A>::construct
allocator_traits<_Alloc>::construct(__a, _M_ptr(),
std::forward<_Args>(__args)...); // might throw
}

~_Sp_counted_ptr_inplace() noexcept { }

virtual void
_M_dispose() noexcept
{
allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr());
}

// Override because the allocator needs to know the dynamic type
virtual void
_M_destroy() noexcept
{
__allocator_type __a(_M_impl._M_alloc());
__allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
this->~_Sp_counted_ptr_inplace();
}

private:
friend class __shared_count<_Lp>; // To be able to call _M_ptr().

// No longer used, but code compiled against old libstdc++ headers
// might still call it from __shared_ptr ctor to get the pointer out.
virtual void*
_M_get_deleter(const std::type_info& __ti) noexcept override
{
auto __ptr = const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
// Check for the fake type_info first, so we don't try to access it
// as a real type_info object. Otherwise, check if it's the real
// type_info for this class. With RTTI enabled we can check directly,
// or call a library function to do it.
if (&__ti == &_Sp_make_shared_tag::_S_ti()
||
#if __cpp_rtti
__ti == typeid(_Sp_make_shared_tag)
#else
_Sp_make_shared_tag::_S_eq(__ti)
#endif
)
return __ptr;
return nullptr;
}

_Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); }

_Impl _M_impl;
};

// The default deleter for shared_ptr<T[]> and shared_ptr<T[N]>.
struct __sp_array_delete
{
template<typename _Yp>
void operator()(_Yp* __p) const { delete[] __p; }
};

template<_Lock_policy _Lp>
class __shared_count
{
template<typename _Tp>
struct __not_alloc_shared_tag { using type = void; };

template<typename _Tp>
struct __not_alloc_shared_tag<_Sp_alloc_shared_tag<_Tp>> { };

public:
constexpr __shared_count() noexcept : _M_pi(0)
{ }

template<typename _Ptr>
explicit
__shared_count(_Ptr __p) : _M_pi(0)
{
__try
{
_M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
}
__catch(...)
{
delete __p;
__throw_exception_again;
}
}

template<typename _Ptr>
__shared_count(_Ptr __p, /* is_array = */ false_type)
: __shared_count(__p)
{ }

template<typename _Ptr>
__shared_count(_Ptr __p, /* is_array = */ true_type)
: __shared_count(__p, __sp_array_delete{}, allocator<void>())
{ }

template<typename _Ptr, typename _Deleter,
typename = typename __not_alloc_shared_tag<_Deleter>::type>
__shared_count(_Ptr __p, _Deleter __d)
: __shared_count(__p, std::move(__d), allocator<void>())
{ }

template<typename _Ptr, typename _Deleter, typename _Alloc,
typename = typename __not_alloc_shared_tag<_Deleter>::type>
__shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
{
typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
__try
{
typename _Sp_cd_type::__allocator_type __a2(__a);
auto __guard = std::__allocate_guarded(__a2);
_Sp_cd_type* __mem = __guard.get();
::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a));
_M_pi = __mem;
__guard = nullptr;
}
__catch(...)
{
__d(__p); // Call _Deleter on __p.
__throw_exception_again;
}
}

template<typename _Tp, typename _Alloc, typename... _Args>
__shared_count(_Tp*& __p, _Sp_alloc_shared_tag<_Alloc> __a,
_Args&&... __args)
{
typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
typename _Sp_cp_type::__allocator_type __a2(__a._M_a);
auto __guard = std::__allocate_guarded(__a2);
_Sp_cp_type* __mem = __guard.get();
auto __pi = ::new (__mem)
_Sp_cp_type(__a._M_a, std::forward<_Args>(__args)...);
__guard = nullptr;
_M_pi = __pi;
__p = __pi->_M_ptr();
}

#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
// Special case for auto_ptr<_Tp> to provide the strong guarantee.
template<typename _Tp>
explicit
__shared_count(std::auto_ptr<_Tp>&& __r);
#pragma GCC diagnostic pop
#endif

// Special case for unique_ptr<_Tp,_Del> to provide the strong guarantee.
template<typename _Tp, typename _Del>
explicit
__shared_count(std::unique_ptr<_Tp, _Del>&& __r) : _M_pi(0)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2415. Inconsistency between unique_ptr and shared_ptr
if (__r.get() == nullptr)
return;

using _Ptr = typename unique_ptr<_Tp, _Del>::pointer;
using _Del2 = typename conditional<is_reference<_Del>::value,
reference_wrapper<typename remove_reference<_Del>::type>,
_Del>::type;
using _Sp_cd_type
= _Sp_counted_deleter<_Ptr, _Del2, allocator<void>, _Lp>;
using _Alloc = allocator<_Sp_cd_type>;
using _Alloc_traits = allocator_traits<_Alloc>;
_Alloc __a;
_Sp_cd_type* __mem = _Alloc_traits::allocate(__a, 1);
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3548. shared_ptr construction from unique_ptr should move
// (not copy) the deleter
_Alloc_traits::construct(__a, __mem, __r.release(),
std::forward<_Del>(__r.get_deleter()));
_M_pi = __mem;
}

// Throw bad_weak_ptr when __r._M_get_use_count() == 0.
explicit __shared_count(const __weak_count<_Lp>& __r);

// Does not throw if __r._M_get_use_count() == 0, caller must check.
explicit
__shared_count(const __weak_count<_Lp>& __r, std::nothrow_t) noexcept;

~__shared_count() noexcept
{
if (_M_pi != nullptr)
_M_pi->_M_release();
}

__shared_count(const __shared_count& __r) noexcept
: _M_pi(__r._M_pi)
{
if (_M_pi != nullptr)
_M_pi->_M_add_ref_copy();
}

__shared_count&
operator=(const __shared_count& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != _M_pi)
{
if (__tmp != nullptr)
__tmp->_M_add_ref_copy();
if (_M_pi != nullptr)
_M_pi->_M_release();
_M_pi = __tmp;
}
return *this;
}

void
_M_swap(__shared_count& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
__r._M_pi = _M_pi;
_M_pi = __tmp;
}

long
_M_get_use_count() const noexcept
{ return _M_pi ? _M_pi->_M_get_use_count() : 0; }

bool
_M_unique() const noexcept
{ return this->_M_get_use_count() == 1; }

void*
_M_get_deleter(const std::type_info& __ti) const noexcept
{ return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr; }

bool
_M_less(const __shared_count& __rhs) const noexcept
{ return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }

bool
_M_less(const __weak_count<_Lp>& __rhs) const noexcept
{ return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }

// Friend function injected into enclosing namespace and found by ADL
friend inline bool
operator==(const __shared_count& __a, const __shared_count& __b) noexcept
{ return __a._M_pi == __b._M_pi; }

private:
friend class __weak_count<_Lp>;

_Sp_counted_base<_Lp>* _M_pi;
};


template<_Lock_policy _Lp>
class __weak_count
{
public:
constexpr __weak_count() noexcept : _M_pi(nullptr)
{ }

__weak_count(const __shared_count<_Lp>& __r) noexcept
: _M_pi(__r._M_pi)
{
if (_M_pi != nullptr)
_M_pi->_M_weak_add_ref();
}

__weak_count(const __weak_count& __r) noexcept
: _M_pi(__r._M_pi)
{
if (_M_pi != nullptr)
_M_pi->_M_weak_add_ref();
}

__weak_count(__weak_count&& __r) noexcept
: _M_pi(__r._M_pi)
{ __r._M_pi = nullptr; }

~__weak_count() noexcept
{
if (_M_pi != nullptr)
_M_pi->_M_weak_release();
}

__weak_count&
operator=(const __shared_count<_Lp>& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != nullptr)
__tmp->_M_weak_add_ref();
if (_M_pi != nullptr)
_M_pi->_M_weak_release();
_M_pi = __tmp;
return *this;
}

__weak_count&
operator=(const __weak_count& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != nullptr)
__tmp->_M_weak_add_ref();
if (_M_pi != nullptr)
_M_pi->_M_weak_release();
_M_pi = __tmp;
return *this;
}

__weak_count&
operator=(__weak_count&& __r) noexcept
{
if (_M_pi != nullptr)
_M_pi->_M_weak_release();
_M_pi = __r._M_pi;
__r._M_pi = nullptr;
return *this;
}

void
_M_swap(__weak_count& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
__r._M_pi = _M_pi;
_M_pi = __tmp;
}

long
_M_get_use_count() const noexcept
{ return _M_pi != nullptr ? _M_pi->_M_get_use_count() : 0; }

bool
_M_less(const __weak_count& __rhs) const noexcept
{ return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }

bool
_M_less(const __shared_count<_Lp>& __rhs) const noexcept
{ return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }

// Friend function injected into enclosing namespace and found by ADL
friend inline bool
operator==(const __weak_count& __a, const __weak_count& __b) noexcept
{ return __a._M_pi == __b._M_pi; }

private:
friend class __shared_count<_Lp>;

_Sp_counted_base<_Lp>* _M_pi;
};

// Now that __weak_count is defined we can define this constructor:
template<_Lock_policy _Lp>
inline
__shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r)
: _M_pi(__r._M_pi)
{
if (_M_pi == nullptr || !_M_pi->_M_add_ref_lock_nothrow())
__throw_bad_weak_ptr();
}

// Now that __weak_count is defined we can define this constructor:
template<_Lock_policy _Lp>
inline
__shared_count<_Lp>::
__shared_count(const __weak_count<_Lp>& __r, std::nothrow_t) noexcept
: _M_pi(__r._M_pi)
{
if (_M_pi && !_M_pi->_M_add_ref_lock_nothrow())
_M_pi = nullptr;
}

#define __cpp_lib_shared_ptr_arrays 201611L

// Helper traits for shared_ptr of array:

// A pointer type Y* is said to be compatible with a pointer type T* when
// either Y* is convertible to T* or Y is U[N] and T is U cv [].
template<typename _Yp_ptr, typename _Tp_ptr>
struct __sp_compatible_with
: false_type
{ };

template<typename _Yp, typename _Tp>
struct __sp_compatible_with<_Yp*, _Tp*>
: is_convertible<_Yp*, _Tp*>::type
{ };

template<typename _Up, size_t _Nm>
struct __sp_compatible_with<_Up(*)[_Nm], _Up(*)[]>
: true_type
{ };

template<typename _Up, size_t _Nm>
struct __sp_compatible_with<_Up(*)[_Nm], const _Up(*)[]>
: true_type
{ };

template<typename _Up, size_t _Nm>
struct __sp_compatible_with<_Up(*)[_Nm], volatile _Up(*)[]>
: true_type
{ };

template<typename _Up, size_t _Nm>
struct __sp_compatible_with<_Up(*)[_Nm], const volatile _Up(*)[]>
: true_type
{ };

// Test conversion from Y(*)[N] to U(*)[N] without forming invalid type Y[N].
template<typename _Up, size_t _Nm, typename _Yp, typename = void>
struct __sp_is_constructible_arrN
: false_type
{ };

template<typename _Up, size_t _Nm, typename _Yp>
struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>>
: is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type
{ };

// Test conversion from Y(*)[] to U(*)[] without forming invalid type Y[].
template<typename _Up, typename _Yp, typename = void>
struct __sp_is_constructible_arr
: false_type
{ };

template<typename _Up, typename _Yp>
struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>>
: is_convertible<_Yp(*)[], _Up(*)[]>::type
{ };

// Trait to check if shared_ptr<T> can be constructed from Y*.
template<typename _Tp, typename _Yp>
struct __sp_is_constructible;

// When T is U[N], Y(*)[N] shall be convertible to T*;
template<typename _Up, size_t _Nm, typename _Yp>
struct __sp_is_constructible<_Up[_Nm], _Yp>
: __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type
{ };

// when T is U[], Y(*)[] shall be convertible to T*;
template<typename _Up, typename _Yp>
struct __sp_is_constructible<_Up[], _Yp>
: __sp_is_constructible_arr<_Up, _Yp>::type
{ };

// otherwise, Y* shall be convertible to T*.
template<typename _Tp, typename _Yp>
struct __sp_is_constructible
: is_convertible<_Yp*, _Tp*>::type
{ };


// Define operator* and operator-> for shared_ptr<T>.
template<typename _Tp, _Lock_policy _Lp,
bool = is_array<_Tp>::value, bool = is_void<_Tp>::value>
class __shared_ptr_access
{
public:
using element_type = _Tp;

element_type&
operator*() const noexcept
{
__glibcxx_assert(_M_get() != nullptr);
return *_M_get();
}

element_type*
operator->() const noexcept
{
_GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
return _M_get();
}

private:
element_type*
_M_get() const noexcept
{ return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
};

// Define operator-> for shared_ptr<cv void>.
template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr_access<_Tp, _Lp, false, true>
{
public:
using element_type = _Tp;

element_type*
operator->() const noexcept
{
auto __ptr = static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get();
_GLIBCXX_DEBUG_PEDASSERT(__ptr != nullptr);
return __ptr;
}
};

// Define operator[] for shared_ptr<T[]> and shared_ptr<T[N]>.
template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr_access<_Tp, _Lp, true, false>
{
public:
using element_type = typename remove_extent<_Tp>::type;

#if __cplusplus <= 201402L
[[__deprecated__("shared_ptr<T[]>::operator* is absent from C++17")]]
element_type&
operator*() const noexcept
{
__glibcxx_assert(_M_get() != nullptr);
return *_M_get();
}

[[__deprecated__("shared_ptr<T[]>::operator-> is absent from C++17")]]
element_type*
operator->() const noexcept
{
_GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
return _M_get();
}
#endif

element_type&
operator[](ptrdiff_t __i) const
{
__glibcxx_assert(_M_get() != nullptr);
__glibcxx_assert(!extent<_Tp>::value || __i < extent<_Tp>::value);
return _M_get()[__i];
}

private:
element_type*
_M_get() const noexcept
{ return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
};

template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr
: public __shared_ptr_access<_Tp, _Lp>
{
public:
using element_type = typename remove_extent<_Tp>::type;

private:
// Constraint for taking ownership of a pointer of type _Yp*:
template<typename _Yp>
using _SafeConv
= typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type;

// Constraint for construction from shared_ptr and weak_ptr:
template<typename _Yp, typename _Res = void>
using _Compatible = typename
enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;

// Constraint for assignment from shared_ptr and weak_ptr:
template<typename _Yp>
using _Assignable = _Compatible<_Yp, __shared_ptr&>;

// Constraint for construction from unique_ptr:
template<typename _Yp, typename _Del, typename _Res = void,
typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer>
using _UniqCompatible = __enable_if_t<__and_<
__sp_compatible_with<_Yp*, _Tp*>,
is_convertible<_Ptr, element_type*>,
is_move_constructible<_Del>
>::value, _Res>;

// Constraint for assignment from unique_ptr:
template<typename _Yp, typename _Del>
using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr&>;

public:

#if __cplusplus > 201402L
using weak_type = __weak_ptr<_Tp, _Lp>;
#endif

constexpr __shared_ptr() noexcept
: _M_ptr(0), _M_refcount()
{ }

template<typename _Yp, typename = _SafeConv<_Yp>>
explicit
__shared_ptr(_Yp* __p)
: _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
{
static_assert( !is_void<_Yp>::value, "incomplete type" );
static_assert( sizeof(_Yp) > 0, "incomplete type" );
_M_enable_shared_from_this_with(__p);
}

template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>>
__shared_ptr(_Yp* __p, _Deleter __d)
: _M_ptr(__p), _M_refcount(__p, std::move(__d))
{
static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
"deleter expression d(p) is well-formed");
_M_enable_shared_from_this_with(__p);
}

template<typename _Yp, typename _Deleter, typename _Alloc,
typename = _SafeConv<_Yp>>
__shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
: _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a))
{
static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
"deleter expression d(p) is well-formed");
_M_enable_shared_from_this_with(__p);
}

template<typename _Deleter>
__shared_ptr(nullptr_t __p, _Deleter __d)
: _M_ptr(0), _M_refcount(__p, std::move(__d))
{ }

template<typename _Deleter, typename _Alloc>
__shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
: _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a))
{ }

// Aliasing constructor
template<typename _Yp>
__shared_ptr(const __shared_ptr<_Yp, _Lp>& __r,
element_type* __p) noexcept
: _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws
{ }

// Aliasing constructor
template<typename _Yp>
__shared_ptr(__shared_ptr<_Yp, _Lp>&& __r,
element_type* __p) noexcept
: _M_ptr(__p), _M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = nullptr;
}

__shared_ptr(const __shared_ptr&) noexcept = default;
__shared_ptr& operator=(const __shared_ptr&) noexcept = default;
~__shared_ptr() = default;

template<typename _Yp, typename = _Compatible<_Yp>>
__shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
{ }

__shared_ptr(__shared_ptr&& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = nullptr;
}

template<typename _Yp, typename = _Compatible<_Yp>>
__shared_ptr(__shared_ptr<_Yp, _Lp>&& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = nullptr;
}

template<typename _Yp, typename = _Compatible<_Yp>>
explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r)
: _M_refcount(__r._M_refcount) // may throw
{
// It is now safe to copy __r._M_ptr, as
// _M_refcount(__r._M_refcount) did not throw.
_M_ptr = __r._M_ptr;
}

// If an exception is thrown this constructor has no effect.
template<typename _Yp, typename _Del,
typename = _UniqCompatible<_Yp, _Del>>
__shared_ptr(unique_ptr<_Yp, _Del>&& __r)
: _M_ptr(__r.get()), _M_refcount()
{
auto __raw = __to_address(__r.get());
_M_refcount = __shared_count<_Lp>(std::move(__r));
_M_enable_shared_from_this_with(__raw);
}

#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED
protected:
// If an exception is thrown this constructor has no effect.
template<typename _Tp1, typename _Del,
typename enable_if<__and_<
__not_<is_array<_Tp>>, is_array<_Tp1>,
is_convertible<typename unique_ptr<_Tp1, _Del>::pointer, _Tp*>
>::value, bool>::type = true>
__shared_ptr(unique_ptr<_Tp1, _Del>&& __r, __sp_array_delete)
: _M_ptr(__r.get()), _M_refcount()
{
auto __raw = __to_address(__r.get());
_M_refcount = __shared_count<_Lp>(std::move(__r));
_M_enable_shared_from_this_with(__raw);
}
public:
#endif

#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
// Postcondition: use_count() == 1 and __r.get() == 0
template<typename _Yp, typename = _Compatible<_Yp>>
__shared_ptr(auto_ptr<_Yp>&& __r);
#pragma GCC diagnostic pop
#endif

constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { }

template<typename _Yp>
_Assignable<_Yp>
operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
{
_M_ptr = __r._M_ptr;
_M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
return *this;
}

#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
template<typename _Yp>
_Assignable<_Yp>
operator=(auto_ptr<_Yp>&& __r)
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
}
#pragma GCC diagnostic pop
#endif

__shared_ptr&
operator=(__shared_ptr&& __r) noexcept
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
}

template<class _Yp>
_Assignable<_Yp>
operator=(__shared_ptr<_Yp, _Lp>&& __r) noexcept
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
}

template<typename _Yp, typename _Del>
_UniqAssignable<_Yp, _Del>
operator=(unique_ptr<_Yp, _Del>&& __r)
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
}

void
reset() noexcept
{ __shared_ptr().swap(*this); }

template<typename _Yp>
_SafeConv<_Yp>
reset(_Yp* __p) // _Yp must be complete.
{
// Catch self-reset errors.
__glibcxx_assert(__p == nullptr || __p != _M_ptr);
__shared_ptr(__p).swap(*this);
}

template<typename _Yp, typename _Deleter>
_SafeConv<_Yp>
reset(_Yp* __p, _Deleter __d)
{ __shared_ptr(__p, std::move(__d)).swap(*this); }

template<typename _Yp, typename _Deleter, typename _Alloc>
_SafeConv<_Yp>
reset(_Yp* __p, _Deleter __d, _Alloc __a)
{ __shared_ptr(__p, std::move(__d), std::move(__a)).swap(*this); }

/// Return the stored pointer.
element_type*
get() const noexcept
{ return _M_ptr; }

/// Return true if the stored pointer is not null.
explicit operator bool() const noexcept
{ return _M_ptr != nullptr; }

/// Return true if use_count() == 1.
bool
unique() const noexcept
{ return _M_refcount._M_unique(); }

/// If *this owns a pointer, return the number of owners, otherwise zero.
long
use_count() const noexcept
{ return _M_refcount._M_get_use_count(); }

/// Exchange both the owned pointer and the stored pointer.
void
swap(__shared_ptr<_Tp, _Lp>& __other) noexcept
{
std::swap(_M_ptr, __other._M_ptr);
_M_refcount._M_swap(__other._M_refcount);
}

/** @brief Define an ordering based on ownership.
*
* This function defines a strict weak ordering between two shared_ptr
* or weak_ptr objects, such that one object is less than the other
* unless they share ownership of the same pointer, or are both empty.
* @{
*/
template<typename _Tp1>
bool
owner_before(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept
{ return _M_refcount._M_less(__rhs._M_refcount); }

template<typename _Tp1>
bool
owner_before(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept
{ return _M_refcount._M_less(__rhs._M_refcount); }
/// @}

protected:
// This constructor is non-standard, it is used by allocate_shared.
template<typename _Alloc, typename... _Args>
__shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args)
: _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward<_Args>(__args)...)
{ _M_enable_shared_from_this_with(_M_ptr); }

template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
typename... _Args>
friend __shared_ptr<_Tp1, _Lp1>
__allocate_shared(const _Alloc& __a, _Args&&... __args);

// This constructor is used by __weak_ptr::lock() and
// shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t).
__shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t) noexcept
: _M_refcount(__r._M_refcount, std::nothrow)
{
_M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr;
}

friend class __weak_ptr<_Tp, _Lp>;

private:

template<typename _Yp>
using __esft_base_t = decltype(__enable_shared_from_this_base(
std::declval<const __shared_count<_Lp>&>(),
std::declval<_Yp*>()));

// Detect an accessible and unambiguous enable_shared_from_this base.
template<typename _Yp, typename = void>
struct __has_esft_base
: false_type { };

template<typename _Yp>
struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>>
: __not_<is_array<_Tp>> { }; // No enable shared_from_this for arrays

template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
typename enable_if<__has_esft_base<_Yp2>::value>::type
_M_enable_shared_from_this_with(_Yp* __p) noexcept
{
if (auto __base = __enable_shared_from_this_base(_M_refcount, __p))
__base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount);
}

template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
typename enable_if<!__has_esft_base<_Yp2>::value>::type
_M_enable_shared_from_this_with(_Yp*) noexcept
{ }

void*
_M_get_deleter(const std::type_info& __ti) const noexcept
{ return _M_refcount._M_get_deleter(__ti); }

template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;

template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept;

template<typename _Del, typename _Tp1>
friend _Del* get_deleter(const shared_ptr<_Tp1>&) noexcept;

element_type* _M_ptr; // Contained pointer.
__shared_count<_Lp> _M_refcount; // Reference counter.
};


// 20.7.2.2.7 shared_ptr comparisons
template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
inline bool
operator==(const __shared_ptr<_Tp1, _Lp>& __a,
const __shared_ptr<_Tp2, _Lp>& __b) noexcept
{ return __a.get() == __b.get(); }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator==(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
{ return !__a; }

#ifdef __cpp_lib_three_way_comparison
template<typename _Tp, typename _Up, _Lock_policy _Lp>
inline strong_ordering
operator<=>(const __shared_ptr<_Tp, _Lp>& __a,
const __shared_ptr<_Up, _Lp>& __b) noexcept
{ return compare_three_way()(__a.get(), __b.get()); }

template<typename _Tp, _Lock_policy _Lp>
inline strong_ordering
operator<=>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
{
using pointer = typename __shared_ptr<_Tp, _Lp>::element_type*;
return compare_three_way()(__a.get(), static_cast<pointer>(nullptr));
}
#else
template<typename _Tp, _Lock_policy _Lp>
inline bool
operator==(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
{ return !__a; }

template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
inline bool
operator!=(const __shared_ptr<_Tp1, _Lp>& __a,
const __shared_ptr<_Tp2, _Lp>& __b) noexcept
{ return __a.get() != __b.get(); }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator!=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
{ return (bool)__a; }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator!=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
{ return (bool)__a; }

template<typename _Tp, typename _Up, _Lock_policy _Lp>
inline bool
operator<(const __shared_ptr<_Tp, _Lp>& __a,
const __shared_ptr<_Up, _Lp>& __b) noexcept
{
using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
using _Up_elt = typename __shared_ptr<_Up, _Lp>::element_type;
using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type;
return less<_Vp>()(__a.get(), __b.get());
}

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator<(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
{
using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
return less<_Tp_elt*>()(__a.get(), nullptr);
}

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator<(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
{
using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
return less<_Tp_elt*>()(nullptr, __a.get());
}

template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
inline bool
operator<=(const __shared_ptr<_Tp1, _Lp>& __a,
const __shared_ptr<_Tp2, _Lp>& __b) noexcept
{ return !(__b < __a); }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator<=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
{ return !(nullptr < __a); }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator<=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
{ return !(__a < nullptr); }

template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
inline bool
operator>(const __shared_ptr<_Tp1, _Lp>& __a,
const __shared_ptr<_Tp2, _Lp>& __b) noexcept
{ return (__b < __a); }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
{ return nullptr < __a; }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator>(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
{ return __a < nullptr; }

template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
inline bool
operator>=(const __shared_ptr<_Tp1, _Lp>& __a,
const __shared_ptr<_Tp2, _Lp>& __b) noexcept
{ return !(__a < __b); }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator>=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
{ return !(__a < nullptr); }

template<typename _Tp, _Lock_policy _Lp>
inline bool
operator>=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
{ return !(nullptr < __a); }
#endif // three-way comparison

// 20.7.2.2.8 shared_ptr specialized algorithms.
template<typename _Tp, _Lock_policy _Lp>
inline void
swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b) noexcept
{ __a.swap(__b); }

// 20.7.2.2.9 shared_ptr casts

// The seemingly equivalent code:
// shared_ptr<_Tp, _Lp>(static_cast<_Tp*>(__r.get()))
// will eventually result in undefined behaviour, attempting to
// delete the same object twice.
/// static_pointer_cast
template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
{
using _Sp = __shared_ptr<_Tp, _Lp>;
return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
}

// The seemingly equivalent code:
// shared_ptr<_Tp, _Lp>(const_cast<_Tp*>(__r.get()))
// will eventually result in undefined behaviour, attempting to
// delete the same object twice.
/// const_pointer_cast
template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
{
using _Sp = __shared_ptr<_Tp, _Lp>;
return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
}

// The seemingly equivalent code:
// shared_ptr<_Tp, _Lp>(dynamic_cast<_Tp*>(__r.get()))
// will eventually result in undefined behaviour, attempting to
// delete the same object twice.
/// dynamic_pointer_cast
template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
{
using _Sp = __shared_ptr<_Tp, _Lp>;
if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
return _Sp(__r, __p);
return _Sp();
}

#if __cplusplus > 201402L
template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
reinterpret_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
{
using _Sp = __shared_ptr<_Tp, _Lp>;
return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
}
#endif

template<typename _Tp, _Lock_policy _Lp>
class __weak_ptr
{
template<typename _Yp, typename _Res = void>
using _Compatible = typename
enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;

// Constraint for assignment from shared_ptr and weak_ptr:
template<typename _Yp>
using _Assignable = _Compatible<_Yp, __weak_ptr&>;

public:
using element_type = typename remove_extent<_Tp>::type;

constexpr __weak_ptr() noexcept
: _M_ptr(nullptr), _M_refcount()
{ }

__weak_ptr(const __weak_ptr&) noexcept = default;

~__weak_ptr() = default;

// The "obvious" converting constructor implementation:
//
// template<typename _Tp1>
// __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
// : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
// { }
//
// has a serious problem.
//
// __r._M_ptr may already have been invalidated. The _M_ptr(__r._M_ptr)
// conversion may require access to *__r._M_ptr (virtual inheritance).
//
// It is not possible to avoid spurious access violations since
// in multithreaded programs __r._M_ptr may be invalidated at any point.
template<typename _Yp, typename = _Compatible<_Yp>>
__weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept
: _M_refcount(__r._M_refcount)
{ _M_ptr = __r.lock().get(); }

template<typename _Yp, typename = _Compatible<_Yp>>
__weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
{ }

__weak_ptr(__weak_ptr&& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount))
{ __r._M_ptr = nullptr; }

template<typename _Yp, typename = _Compatible<_Yp>>
__weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept
: _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount))
{ __r._M_ptr = nullptr; }

__weak_ptr&
operator=(const __weak_ptr& __r) noexcept = default;

template<typename _Yp>
_Assignable<_Yp>
operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept
{
_M_ptr = __r.lock().get();
_M_refcount = __r._M_refcount;
return *this;
}

template<typename _Yp>
_Assignable<_Yp>
operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
{
_M_ptr = __r._M_ptr;
_M_refcount = __r._M_refcount;
return *this;
}

__weak_ptr&
operator=(__weak_ptr&& __r) noexcept
{
__weak_ptr(std::move(__r)).swap(*this);
return *this;
}

template<typename _Yp>
_Assignable<_Yp>
operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept
{
_M_ptr = __r.lock().get();
_M_refcount = std::move(__r._M_refcount);
__r._M_ptr = nullptr;
return *this;
}

__shared_ptr<_Tp, _Lp>
lock() const noexcept
{ return __shared_ptr<element_type, _Lp>(*this, std::nothrow); }

long
use_count() const noexcept
{ return _M_refcount._M_get_use_count(); }

bool
expired() const noexcept
{ return _M_refcount._M_get_use_count() == 0; }

template<typename _Tp1>
bool
owner_before(const __shared_ptr<_Tp1, _Lp>& __rhs) const noexcept
{ return _M_refcount._M_less(__rhs._M_refcount); }

template<typename _Tp1>
bool
owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept
{ return _M_refcount._M_less(__rhs._M_refcount); }

void
reset() noexcept
{ __weak_ptr().swap(*this); }

void
swap(__weak_ptr& __s) noexcept
{
std::swap(_M_ptr, __s._M_ptr);
_M_refcount._M_swap(__s._M_refcount);
}

private:
// Used by __enable_shared_from_this.
void
_M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount) noexcept
{
if (use_count() == 0)
{
_M_ptr = __ptr;
_M_refcount = __refcount;
}
}

template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
friend class __enable_shared_from_this<_Tp, _Lp>;
friend class enable_shared_from_this<_Tp>;

element_type* _M_ptr; // Contained pointer.
__weak_count<_Lp> _M_refcount; // Reference counter.
};

// 20.7.2.3.6 weak_ptr specialized algorithms.
template<typename _Tp, _Lock_policy _Lp>
inline void
swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b) noexcept
{ __a.swap(__b); }

template<typename _Tp, typename _Tp1>
struct _Sp_owner_less : public binary_function<_Tp, _Tp, bool>
{
bool
operator()(const _Tp& __lhs, const _Tp& __rhs) const noexcept
{ return __lhs.owner_before(__rhs); }

bool
operator()(const _Tp& __lhs, const _Tp1& __rhs) const noexcept
{ return __lhs.owner_before(__rhs); }

bool
operator()(const _Tp1& __lhs, const _Tp& __rhs) const noexcept
{ return __lhs.owner_before(__rhs); }
};

template<>
struct _Sp_owner_less<void, void>
{
template<typename _Tp, typename _Up>
auto
operator()(const _Tp& __lhs, const _Up& __rhs) const noexcept
-> decltype(__lhs.owner_before(__rhs))
{ return __lhs.owner_before(__rhs); }

using is_transparent = void;
};

template<typename _Tp, _Lock_policy _Lp>
struct owner_less<__shared_ptr<_Tp, _Lp>>
: public _Sp_owner_less<__shared_ptr<_Tp, _Lp>, __weak_ptr<_Tp, _Lp>>
{ };

template<typename _Tp, _Lock_policy _Lp>
struct owner_less<__weak_ptr<_Tp, _Lp>>
: public _Sp_owner_less<__weak_ptr<_Tp, _Lp>, __shared_ptr<_Tp, _Lp>>
{ };


template<typename _Tp, _Lock_policy _Lp>
class __enable_shared_from_this
{
protected:
constexpr __enable_shared_from_this() noexcept { }

__enable_shared_from_this(const __enable_shared_from_this&) noexcept { }

__enable_shared_from_this&
operator=(const __enable_shared_from_this&) noexcept
{ return *this; }

~__enable_shared_from_this() { }

public:
__shared_ptr<_Tp, _Lp>
shared_from_this()
{ return __shared_ptr<_Tp, _Lp>(this->_M_weak_this); }

__shared_ptr<const _Tp, _Lp>
shared_from_this() const
{ return __shared_ptr<const _Tp, _Lp>(this->_M_weak_this); }

#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
__weak_ptr<_Tp, _Lp>
weak_from_this() noexcept
{ return this->_M_weak_this; }

__weak_ptr<const _Tp, _Lp>
weak_from_this() const noexcept
{ return this->_M_weak_this; }
#endif

private:
template<typename _Tp1>
void
_M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const noexcept
{ _M_weak_this._M_assign(__p, __n); }

friend const __enable_shared_from_this*
__enable_shared_from_this_base(const __shared_count<_Lp>&,
const __enable_shared_from_this* __p)
{ return __p; }

template<typename, _Lock_policy>
friend class __shared_ptr;

mutable __weak_ptr<_Tp, _Lp> _M_weak_this;
};

template<typename _Tp, _Lock_policy _Lp = __default_lock_policy,
typename _Alloc, typename... _Args>
inline __shared_ptr<_Tp, _Lp>
__allocate_shared(const _Alloc& __a, _Args&&... __args)
{
static_assert(!is_array<_Tp>::value, "make_shared<T[]> not supported");

return __shared_ptr<_Tp, _Lp>(_Sp_alloc_shared_tag<_Alloc>{__a},
std::forward<_Args>(__args)...);
}

template<typename _Tp, _Lock_policy _Lp = __default_lock_policy,
typename... _Args>
inline __shared_ptr<_Tp, _Lp>
__make_shared(_Args&&... __args)
{
typedef typename std::remove_const<_Tp>::type _Tp_nc;
return std::__allocate_shared<_Tp, _Lp>(std::allocator<_Tp_nc>(),
std::forward<_Args>(__args)...);
}

/// std::hash specialization for __shared_ptr.
template<typename _Tp, _Lock_policy _Lp>
struct hash<__shared_ptr<_Tp, _Lp>>
: public __hash_base<size_t, __shared_ptr<_Tp, _Lp>>
{
size_t
operator()(const __shared_ptr<_Tp, _Lp>& __s) const noexcept
{
return hash<typename __shared_ptr<_Tp, _Lp>::element_type*>()(
__s.get());
}
};

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

#endif // _SHARED_PTR_BASE_H
shared_ptr_atomic.h
shared_ptr_atomic.hview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
// shared_ptr atomic access -*- C++ -*-

// Copyright (C) 2014-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.

/** @file bits/shared_ptr_atomic.h
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{memory}
*/

#ifndef _SHARED_PTR_ATOMIC_H
#define _SHARED_PTR_ATOMIC_H 1

#include <bits/atomic_base.h>

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

/**
* @addtogroup pointer_abstractions
* @{
*/
/// @relates shared_ptr @{

/// @cond undocumented

struct _Sp_locker
{
_Sp_locker(const _Sp_locker&) = delete;
_Sp_locker& operator=(const _Sp_locker&) = delete;

#ifdef __GTHREADS
explicit
_Sp_locker(const void*) noexcept;
_Sp_locker(const void*, const void*) noexcept;
~_Sp_locker();

private:
unsigned char _M_key1;
unsigned char _M_key2;
#else
explicit _Sp_locker(const void*, const void* = nullptr) { }
#endif
};

/// @endcond

/**
* @brief Report whether shared_ptr atomic operations are lock-free.
* @param __p A non-null pointer to a shared_ptr object.
* @return True if atomic access to @c *__p is lock-free, false otherwise.
* @{
*/
template<typename _Tp, _Lock_policy _Lp>
inline bool
atomic_is_lock_free(const __shared_ptr<_Tp, _Lp>* __p)
{
#ifdef __GTHREADS
return __gthread_active_p() == 0;
#else
return true;
#endif
}

template<typename _Tp>
inline bool
atomic_is_lock_free(const shared_ptr<_Tp>* __p)
{ return std::atomic_is_lock_free<_Tp, __default_lock_policy>(__p); }

/// @}

/**
* @brief Atomic load for shared_ptr objects.
* @param __p A non-null pointer to a shared_ptr object.
* @return @c *__p
*
* The memory order shall not be @c memory_order_release or
* @c memory_order_acq_rel.
* @{
*/
template<typename _Tp>
inline shared_ptr<_Tp>
atomic_load_explicit(const shared_ptr<_Tp>* __p, memory_order)
{
_Sp_locker __lock{__p};
return *__p;
}

template<typename _Tp>
inline shared_ptr<_Tp>
atomic_load(const shared_ptr<_Tp>* __p)
{ return std::atomic_load_explicit(__p, memory_order_seq_cst); }

template<typename _Tp, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
atomic_load_explicit(const __shared_ptr<_Tp, _Lp>* __p, memory_order)
{
_Sp_locker __lock{__p};
return *__p;
}

template<typename _Tp, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
atomic_load(const __shared_ptr<_Tp, _Lp>* __p)
{ return std::atomic_load_explicit(__p, memory_order_seq_cst); }
/// @}

/**
* @brief Atomic store for shared_ptr objects.
* @param __p A non-null pointer to a shared_ptr object.
* @param __r The value to store.
*
* The memory order shall not be @c memory_order_acquire or
* @c memory_order_acq_rel.
* @{
*/
template<typename _Tp>
inline void
atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r,
memory_order)
{
_Sp_locker __lock{__p};
__p->swap(__r); // use swap so that **__p not destroyed while lock held
}

template<typename _Tp>
inline void
atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r)
{ std::atomic_store_explicit(__p, std::move(__r), memory_order_seq_cst); }

template<typename _Tp, _Lock_policy _Lp>
inline void
atomic_store_explicit(__shared_ptr<_Tp, _Lp>* __p,
__shared_ptr<_Tp, _Lp> __r,
memory_order)
{
_Sp_locker __lock{__p};
__p->swap(__r); // use swap so that **__p not destroyed while lock held
}

template<typename _Tp, _Lock_policy _Lp>
inline void
atomic_store(__shared_ptr<_Tp, _Lp>* __p, __shared_ptr<_Tp, _Lp> __r)
{ std::atomic_store_explicit(__p, std::move(__r), memory_order_seq_cst); }
/// @}

/**
* @brief Atomic exchange for shared_ptr objects.
* @param __p A non-null pointer to a shared_ptr object.
* @param __r New value to store in @c *__p.
* @return The original value of @c *__p
* @{
*/
template<typename _Tp>
inline shared_ptr<_Tp>
atomic_exchange_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r,
memory_order)
{
_Sp_locker __lock{__p};
__p->swap(__r);
return __r;
}

template<typename _Tp>
inline shared_ptr<_Tp>
atomic_exchange(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r)
{
return std::atomic_exchange_explicit(__p, std::move(__r),
memory_order_seq_cst);
}

template<typename _Tp, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
atomic_exchange_explicit(__shared_ptr<_Tp, _Lp>* __p,
__shared_ptr<_Tp, _Lp> __r,
memory_order)
{
_Sp_locker __lock{__p};
__p->swap(__r);
return __r;
}

template<typename _Tp, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
atomic_exchange(__shared_ptr<_Tp, _Lp>* __p, __shared_ptr<_Tp, _Lp> __r)
{
return std::atomic_exchange_explicit(__p, std::move(__r),
memory_order_seq_cst);
}
/// @}

/**
* @brief Atomic compare-and-swap for shared_ptr objects.
* @param __p A non-null pointer to a shared_ptr object.
* @param __v A non-null pointer to a shared_ptr object.
* @param __w A non-null pointer to a shared_ptr object.
* @return True if @c *__p was equivalent to @c *__v, false otherwise.
*
* The memory order for failure shall not be @c memory_order_release or
* @c memory_order_acq_rel, or stronger than the memory order for success.
* @{
*/
template<typename _Tp>
bool
atomic_compare_exchange_strong_explicit(shared_ptr<_Tp>* __p,
shared_ptr<_Tp>* __v,
shared_ptr<_Tp> __w,
memory_order,
memory_order)
{
shared_ptr<_Tp> __x; // goes out of scope after __lock
_Sp_locker __lock{__p, __v};
owner_less<shared_ptr<_Tp>> __less;
if (*__p == *__v && !__less(*__p, *__v) && !__less(*__v, *__p))
{
__x = std::move(*__p);
*__p = std::move(__w);
return true;
}
__x = std::move(*__v);
*__v = *__p;
return false;
}

template<typename _Tp>
inline bool
atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v,
shared_ptr<_Tp> __w)
{
return std::atomic_compare_exchange_strong_explicit(__p, __v,
std::move(__w), memory_order_seq_cst, memory_order_seq_cst);
}

template<typename _Tp>
inline bool
atomic_compare_exchange_weak_explicit(shared_ptr<_Tp>* __p,
shared_ptr<_Tp>* __v,
shared_ptr<_Tp> __w,
memory_order __success,
memory_order __failure)
{
return std::atomic_compare_exchange_strong_explicit(__p, __v,
std::move(__w), __success, __failure);
}

template<typename _Tp>
inline bool
atomic_compare_exchange_weak(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v,
shared_ptr<_Tp> __w)
{
return std::atomic_compare_exchange_weak_explicit(__p, __v,
std::move(__w), memory_order_seq_cst, memory_order_seq_cst);
}

template<typename _Tp, _Lock_policy _Lp>
bool
atomic_compare_exchange_strong_explicit(__shared_ptr<_Tp, _Lp>* __p,
__shared_ptr<_Tp, _Lp>* __v,
__shared_ptr<_Tp, _Lp> __w,
memory_order,
memory_order)
{
__shared_ptr<_Tp, _Lp> __x; // goes out of scope after __lock
_Sp_locker __lock{__p, __v};
owner_less<__shared_ptr<_Tp, _Lp>> __less;
if (*__p == *__v && !__less(*__p, *__v) && !__less(*__v, *__p))
{
__x = std::move(*__p);
*__p = std::move(__w);
return true;
}
__x = std::move(*__v);
*__v = *__p;
return false;
}

template<typename _Tp, _Lock_policy _Lp>
inline bool
atomic_compare_exchange_strong(__shared_ptr<_Tp, _Lp>* __p,
__shared_ptr<_Tp, _Lp>* __v,
__shared_ptr<_Tp, _Lp> __w)
{
return std::atomic_compare_exchange_strong_explicit(__p, __v,
std::move(__w), memory_order_seq_cst, memory_order_seq_cst);
}

template<typename _Tp, _Lock_policy _Lp>
inline bool
atomic_compare_exchange_weak_explicit(__shared_ptr<_Tp, _Lp>* __p,
__shared_ptr<_Tp, _Lp>* __v,
__shared_ptr<_Tp, _Lp> __w,
memory_order __success,
memory_order __failure)
{
return std::atomic_compare_exchange_strong_explicit(__p, __v,
std::move(__w), __success, __failure);
}

template<typename _Tp, _Lock_policy _Lp>
inline bool
atomic_compare_exchange_weak(__shared_ptr<_Tp, _Lp>* __p,
__shared_ptr<_Tp, _Lp>* __v,
__shared_ptr<_Tp, _Lp> __w)
{
return std::atomic_compare_exchange_weak_explicit(__p, __v,
std::move(__w), memory_order_seq_cst, memory_order_seq_cst);
}
/// @}

/// @} relates shared_ptr
/// @} group pointer_abstractions

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

#endif // _SHARED_PTR_ATOMIC_H