Skip to content

Commit f3f03ce

Browse files
committed
1. 补充 std::thread 源码解析中构造函数的约束
2. 修改第二章失效的 libc++ 超链接
1 parent cfa137e commit f3f03ce

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

md/02使用线程.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ thread _Impl;
889889
stop_source _Ssource;
890890
```
891891
892-
[MSVC STL](https://github.com/microsoft/STL/blob/23344e2/stl/inc/thread#L435-L436)[libstdc++](https://github.com/gcc-mirror/gcc/blob/1a5e4dd/libstdc%2B%2B-v3/include/std/thread#L290-L291)[libc++](https://github.com/llvm/llvm-project/blob/7162fd7/libcxx/include/__thread/jthread.h#L125-L126) 均是如此。
892+
[MSVC STL](https://github.com/microsoft/STL/blob/23344e2/stl/inc/thread#L435-L436)[libstdc++](https://github.com/gcc-mirror/gcc/blob/1a5e4dd/libstdc%2B%2B-v3/include/std/thread#L290-L291)[libc++](https://github.com/llvm/llvm-project/blob/04f01a2/libcxx/include/__thread/jthread.h#L124-L125) 均是如此。
893893
894894
`stop_source` 通常占 8 字节,先前 `std::thread` 源码解析详细聊过其不同标准库对其保有的成员不同,简单来说也就是 64 位环境,大小为 16 或者 8。也就是 `sizeof(std::jthread)` 的值相比 `std::thread` 会多 8 ,为 `24``16`
895895

md/详细分析/01thread的构造与源码解析.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,37 @@ struct _Thrd_t { // thread identifier for Win32
6868
6969
前三个构造函数都没啥要特别聊的,非常简单,只有第四个构造函数较为复杂,且是我们本章重点,需要详细讲解。(*注意 MSVC 使用标准库的内容很多时候不加 **std::**,脑补一下就行*)
7070
71-
如你所见,这个构造函数本身并没有做什么,它只是一个可变参数成员函数模板,增加了一些 [SFINAE](https://zh.cppreference.com/w/cpp/language/sfinae) 进行约束我们传入的[可调用](https://zh.cppreference.com/w/cpp/named_req/Callable)对象的类型不能是 `std::thread`。函数体中调用了一个函数 [**`_Start`**](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/thread#L72-L87),将我们构造函数的参数全部完美转发,去调用它,这个函数才是我们的重点,如下:
71+
如你所见,这个构造函数本身并没有做什么,它只是一个可变参数成员函数模板,增加了一些 [SFINAE](https://zh.cppreference.com/w/cpp/language/sfinae) 进行约束我们传入的[可调用](https://zh.cppreference.com/w/cpp/named_req/Callable)对象的类型不能是 `std::thread`。关于这个约束你可能有问题,因为 `std::thread` 他并没有 `operator()` 的重载,不是可调用类型,这个 `enable_if_t` 的意义是什么呢?其实很简单,如下:
72+
73+
```cpp
74+
struct X{
75+
X(X&& x)noexcept{}
76+
template <class Fn, class... Args>
77+
X(Fn&& f,Args&&...args){}
78+
X(const X&) = delete;
79+
};
80+
81+
X x{ [] {} };
82+
X x2{ x }; // 选择到了有参构造函数,不导致编译错误
83+
```
84+
85+
以上这段代码可以正常的[通过编译](https://godbolt.org/z/6zhW6xjqP)。这是重载决议的事情,我们知道,`std::thread` 是不可复制的,这种代码自然不应该让它通过编译,选择到我们的有参构造,所以我们添加一个约束让其不能选择到我们的有参构造:
86+
87+
```cpp
88+
template <class Fn, class... Args, std::enable_if_t<!std::is_same_v<std::remove_cvref_t<Fn>, X>, int> = 0>
89+
```
90+
91+
这样,这段代码就会正常的出现[编译错误](https://godbolt.org/z/Mc1h1GcdT),信息如下:
92+
93+
```txt
94+
error C2280: “X::X(const X &)”: 尝试引用已删除的函数
95+
note: 参见“X::X”的声明
96+
note: “X::X(const X &)”: 已隐式删除函数
97+
```
98+
99+
也就满足了我们的要求,重载决议选择到了弃置复制构造函数产生编译错误,这也就是源码中添加约束的目的。
100+
101+
而构造函数体中调用了一个函数 [**`_Start`**](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/thread#L72-L87),将我们构造函数的参数全部完美转发,去调用它,这个函数才是我们的重点,如下:
72102

73103
```cpp
74104
template <class _Fn, class... _Args>

0 commit comments

Comments
 (0)