Skip to content

Commit 7660def

Browse files
committed
Updated to Chapter 11, Section 6
1 parent 2584d55 commit 7660def

17 files changed

+639
-75
lines changed

.vscode/launch.json

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"configurations": [
3+
{
4+
"name": "C/C++: g++.exe build and debug active file",
5+
"type": "cppdbg",
6+
"request": "launch",
7+
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
8+
"args": [],
9+
"stopAtEntry": false,
10+
"cwd": "D:\\msys64\\ucrt64\\bin",
11+
"environment": [],
12+
"externalConsole": false,
13+
"MIMode": "gdb",
14+
"miDebuggerPath": "D:\\msys64\\ucrt64\\bin\\gdb.exe",
15+
"setupCommands": [
16+
{
17+
"description": "Enable pretty-printing for gdb",
18+
"text": "-enable-pretty-printing",
19+
"ignoreFailures": true
20+
},
21+
{
22+
"description": "Set Disassembly Flavor to Intel",
23+
"text": "-gdb-set disassembly-flavor intel",
24+
"ignoreFailures": true
25+
}
26+
],
27+
"preLaunchTask": "C/C++: g++.exe build active file"
28+
}
29+
],
30+
"version": "2.0.0"
31+
}

.vscode/settings.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"xmemory": "cpp",
5151
"xstring": "cpp",
5252
"xtr1common": "cpp",
53-
"xutility": "cpp"
53+
"xutility": "cpp",
54+
"unordered_set": "cpp",
55+
"*.tpp": "cpp"
5456
}
5557
}

README.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@
22

33
> *cppHusky* 的2024年礼
44
5-
此项目第一阶段计划(泛讲篇前七章)已经完成!
5+
此项目第一阶段计划(前七章)已经完成!
66

7-
### 当前进度:泛讲篇第十章完成。参见[Preview](https://github.com/cppHusky/cppHusky-cpp-Tutorial/releases/tag/preview-0-0-9)
7+
### 当前进度:第十一章完成。参见[Preview](https://github.com/cppHusky/cppHusky-cpp-Tutorial/releases/tag/preview-0-0-11)
88

99
我为此规划了一个大致的编章结构,参见[Structure.md](https://github.com/cppHusky/cppHusky-cpp-Tutorial/blob/main/Structure.md)
1010

1111
本书中的每一份正式的示例代码都已打包并存至本项目中!详见[Code in book](https://github.com/cppHusky/cppHusky-cpp-Tutorial/tree/main/code_in_book)
1212

13-
正在疯狂赶进度,还要补充插图和代码,以及布署甲辰年礼解谜。现阶段争取保持每4天更新一章的速度
13+
正在疯狂赶进度,还要补充插图和代码,以及布署甲辰年礼解谜。现阶段争取保持每3天更新一章的速度
1414

1515
如果发现内容有任何疏漏和错误,欢迎来作补充和提出修改意见!可以直接提交到[Issues](https://github.com/cppHusky/cppHusky-cpp-Tutorial/issues)当中。
1616

17-
>自24年1月6日起,共编缉此项目时长为 :[![wakatime](https://wakatime.com/badge/user/018cddbf-c102-44d2-a0f3-463bcf2eef39/project/018cddc4-4445-4bc3-8a9d-c6c933978a2b.svg)](https://wakatime.com/badge/user/018cddbf-c102-44d2-a0f3-463bcf2eef39/project/018cddc4-4445-4bc3-8a9d-c6c933978a2b)
17+
>自24年1月6日起,共编缉此项目时长为 :[![wakatime](https://wakatime.com/badge/user/018cddbf-c102-44d2-a0f3-463bcf2eef39/project/018cddc4-4445-4bc3-8a9d-c6c933978a2b.svg)](https://wakatime.com/badge/user/018cddbf-c102-44d2-a0f3-463bcf2eef39/project/018cddc4-4445-4bc3-8a9d-c6c933978a2b)
18+
19+
(顺便一说,精讲篇不打算写了,留到第三版吧)

code_in_book/11.4-11.6/Definition.tpp

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#pragma once //千万不要遗漏
2-
#include "array.hpp" //这句可以没有,但是为了编译器检查方便,还是包含一下吧
32
#include <algorithm> //包含std::min等实用函数
43
//类模板std::array<T,N>的成员函数及一些非成员函数的定义
54
template<typename T, std::size_t N>

code_in_book/11.4-11.6/Specification.tpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#pragma once //千万不要遗漏
2-
#include "array.hpp" //这句可以没有,但是为了编译器检查方便,还是包含一下吧
32
#include <bitset> //user::array内部的数据需要利用std::bitset来管理
43
namespace user{
54
//array类模板特化部分
@@ -31,8 +30,8 @@ public:
3130
template<std::size_t I, typename U, std::size_t M>
3231
friend const U& get(const array<U, M>&);
3332
//同上
34-
template<std::size_t N, std::size_t M>
35-
friend void swap(array<bool, N>&, array<bool, M>&);
33+
template<std::size_t N1, std::size_t N2>
34+
friend void swap(array<bool, N1>&, array<bool, N2>&);
3635
template<typename, std::size_t>
3736
friend class array;
3837
//声明友元类模板,任何一个array实例都是array<bool,N>的友元

code_in_book/11.4-11.6/array.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ class array {
5050
template<std::size_t I, typename U, std::size_t M>
5151
friend const U& get(const array<U, M>&);
5252
//同上
53-
template<typename T, std::size_t N, std::size_t M>
54-
friend void swap(array<T, N>&, array<T, M>&);
53+
template<typename U, std::size_t N1, std::size_t N2>
54+
friend void swap(array<U, N1>&, array<U, N2>&);
5555
//声明友元(非成员函数),任何两个array<T,N>和array<T,M>可用swap函数交换
5656
template<typename, std::size_t>
5757
friend class array;

code_in_book/11.8-11.9/Definition.tpp

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#pragma once
2+
#include <algorithm>
3+
//非成员函数定义部分
4+
template<typename T>
5+
void user::swap(unique_ptr<T> &lhs, unique_ptr<T> &rhs) {
6+
std::swap(lhs._ptr, rhs._ptr); //只要交换它们底层的指针就行了
7+
}
8+
template<typename T>
9+
std::ostream& user::operator<<(
10+
std::ostream &out,
11+
const user::unique_ptr<T> &ptr
12+
) {
13+
return out << ptr._ptr; //其实就是直接输出ptr内部的指针值,这也正是我们想要的
14+
}
15+
//主模板成员函数定义部分
16+
template<typename T>
17+
user::unique_ptr<T>::unique_ptr(pointer ptr) {
18+
if (record.find(ptr) == record.end()) { //先在记录当中寻找是否有ptr
19+
_ptr = ptr;
20+
record.insert(ptr); //如果没找到,_ptr可以安全赋值,并记录这个值
21+
} //否则什么也不做
22+
}
23+
template<typename T>
24+
user::unique_ptr<T>::~unique_ptr() {
25+
if (record.find(_ptr) != record.end()) { //如果在记录中找到了_ptr
26+
delete _ptr; //回收动态内存
27+
record.erase(_ptr); //清除记录
28+
}
29+
}
30+
template<typename T>
31+
auto user::unique_ptr<T>::release() -> pointer { //用auto来方便我们写返回类型
32+
pointer tmp {_ptr}; //临时变量存值,以便返回
33+
_ptr = nullptr; //_ptr指向空
34+
return tmp;
35+
}
36+
template<typename T>
37+
auto user::unique_ptr<T>::get()const -> pointer {
38+
return _ptr;
39+
}
40+
template<typename T>
41+
void user::unique_ptr<T>::reset(pointer ptr) {
42+
if (record.find(_ptr) != record.end()) { //先清理旧的指针
43+
delete _ptr;
44+
record.erase(_ptr);
45+
_ptr = nullptr; //注意把_ptr置空,否则可能会出现野指针
46+
}
47+
if (record.find(ptr) == record.end()) { //如果新的地址值不在记录当中
48+
_ptr = ptr;
49+
record.erase(_ptr);
50+
} //否则什么也不做
51+
}
52+
template<typename T>
53+
void user::unique_ptr<T>::swap(unique_ptr &ptr) {
54+
std::swap(_ptr, ptr._ptr);
55+
}
56+
//模板特化定义部分
57+
template<typename T>
58+
user::unique_ptr<T[]>::unique_ptr(pointer ptr) {
59+
if (record.find(ptr) == record.end()) { //同上,没什么特别的
60+
_ptr = ptr;
61+
record.insert(ptr);
62+
}
63+
}
64+
template<typename T>
65+
user::unique_ptr<T[]>::~unique_ptr() {
66+
if (record.find(_ptr) != record.end()) {
67+
delete[] _ptr; //一定不要搞错了!
68+
record.erase(_ptr);
69+
}
70+
}
71+
template<typename T>
72+
auto user::unique_ptr<T[]>::release() -> pointer {
73+
pointer tmp {_ptr};
74+
_ptr = nullptr;
75+
return tmp;
76+
}
77+
template<typename T>
78+
auto user::unique_ptr<T[]>::get()const -> pointer {
79+
return _ptr;
80+
}
81+
template<typename T>
82+
void user::unique_ptr<T[]>::reset(pointer ptr) {
83+
if (record.find(_ptr) != record.end()) {
84+
delete[] _ptr; //一定不要搞错了!
85+
record.erase(_ptr);
86+
_ptr = nullptr;
87+
}
88+
if (record.find(ptr) == record.end()) {
89+
_ptr = ptr;
90+
record.erase(_ptr);
91+
}
92+
}
93+
template<typename T>
94+
void user::unique_ptr<T[]>::swap(unique_ptr& ptr) {
95+
std::swap(_ptr, ptr._ptr);
96+
}

code_in_book/11.8-11.9/unique_ptr.hpp

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#pragma once
2+
#include <iostream>
3+
#include <unordered_set>
4+
namespace user {
5+
//类模板与函数模板声明部分
6+
template<typename T>
7+
class unique_ptr; //定义类模板unique_ptr
8+
template<typename T>
9+
class unique_ptr<T[]>; //定义特化unique_ptr<T[]>
10+
template<typename T>
11+
void swap(unique_ptr<T>&, unique_ptr<T>&);
12+
template<typename T>
13+
std::ostream& operator<<(std::ostream&, const unique_ptr<T>&);
14+
//主模板定义部分
15+
template<typename T>
16+
class unique_ptr { //分配动态单对象,使用unique_ptr<T>语法
17+
public:
18+
using pointer = T*; //通过using定义成员类型pointer,公有
19+
using element_type = T; //定义成员类型element_type
20+
private:
21+
pointer _ptr {nullptr}; //pointer类型的私有成员,成员类型pointer必须定义在前面
22+
static std::unordered_set<pointer> record;
23+
public:
24+
explicit unique_ptr(pointer = {nullptr}); //接收pointer类参数,或nullptr
25+
unique_ptr(const unique_ptr&) = delete; //删除拷贝构造函数
26+
~unique_ptr(); //析构函数
27+
unique_ptr& operator=(const unique_ptr&) = delete; //删除拷贝赋值函数
28+
pointer release(); //release函数会把指向改为nullptr
29+
pointer get()const; //get函数不会改变成员;至于透过get()改变内容,那是允许的
30+
void reset(pointer = {nullptr}); //重置指向
31+
operator bool()const { return _ptr != nullptr; } //表明指向是否非空
32+
void swap(unique_ptr&);
33+
element_type& operator*()const { return *get(); } //注意返回值得是引用
34+
pointer operator->()const { return get(); } //注意返回类型得是裸指针或对象
35+
template<typename U>
36+
friend void swap(unique_ptr<U>&, unique_ptr<U>&);
37+
template<typename U>
38+
friend std::ostream& operator<<(std::ostream&, const unique_ptr<U>&);
39+
};
40+
//模板特化定义部分
41+
template<typename T>
42+
class unique_ptr<T[]> { //特化,分配动态数组,使用unique_ptr<T[]>语法
43+
public:
44+
using pointer = T*; //对于T[]来说,它只是意味着分配动态数组,其指针类型还是T*
45+
using element_type = T; //同理,元素类型还是T
46+
private:
47+
pointer _ptr {nullptr};
48+
static std::unordered_set<pointer> record;
49+
public:
50+
explicit unique_ptr(pointer = {nullptr});
51+
unique_ptr(const unique_ptr&) = delete; //删除拷贝构造函数
52+
~unique_ptr();
53+
unique_ptr& operator=(const unique_ptr&) = delete; //删除拷贝赋值函数
54+
pointer release(); //同上
55+
pointer get()const;
56+
void reset(pointer = {nullptr}); //简化版,对继承关系的支持较差
57+
operator bool()const { return _ptr != nullptr; }
58+
void swap(unique_ptr&);
59+
element_type& operator[](std::size_t i)const { return _ptr[i]; }
60+
//下标运算符,访问第i个元素
61+
template<typename U>
62+
friend void swap(unique_ptr<U>&, unique_ptr<U>&);
63+
template<typename U>
64+
friend std::ostream& operator<<(std::ostream&, const unique_ptr<U>&);
65+
};
66+
};
67+
//静态成员变量定义部分
68+
template<typename T>
69+
inline std::unordered_set<
70+
typename user::unique_ptr<T>::pointer //typename关键字说明它是一个类型
71+
> user::unique_ptr<T>::record;
72+
template<typename T>
73+
inline std::unordered_set<
74+
typename user::unique_ptr<T[]>::pointer
75+
> user::unique_ptr<T[]>::record;
76+
#include "Definition.tpp"

generalized_parts/11_templates_and_fundamental_generic_programming/04_friend_instantiation_and_specialization_of_class_templates.tex

+3-3
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ \subsubsection*{函数模板友元}
9292
它的友元声明\footnote{再次提醒读者,函数声明与友元声明是不同的,友元声明只是一种关系声明,它并不会产生函数声明。我们最好把函数声明单独写出来。}是这样的:
9393
\begin{lstlisting}
9494
public:
95-
template<typename T, std::size_t N, std::size_t M>
96-
friend void swap(array<T, N>&, array<T, M>&);
97-
//声明友元(非成员函数),任何两个array<T,N>和array<T,M>可用swap函数交换
95+
template<typename U, std::size_t N1, std::size_t N2>
96+
friend void swap(array<U, N1>&, array<U, N2>&);
97+
//声明友元(非成员函数),任何两个array<U,N1>和array<U,N2>可用swap函数交换
9898
\end{lstlisting}
9999
它的定义是这样的:
100100
\begin{lstlisting}

generalized_parts/11_templates_and_fundamental_generic_programming/05_introduction_to_STL.tex

+2-1
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,8 @@ \subsection*{算法}
360360
\begin{lstlisting}
361361
for (InputIt it = first; it != last; ++it) //效果相同
362362
f(*it);
363-
\end{lstlisting}\par
363+
\end{lstlisting}
364+
\lstinline@std::for_each@ 的用途很多,不过主要是靠函数指针和闭包来实现的,所以我们就放到精讲篇再讲它吧。\par
364365
\lstinline@std::lexicographical_compare@ 也是一个算法。
365366
\begin{lstlisting}
366367
template<class InputIt1, class InputIt2>

0 commit comments

Comments
 (0)