-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
193 lines (95 loc) · 44.7 KB
/
atom.xml
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>ts1989</title>
<icon>http://example.com/icon.png</icon>
<link href="http://example.com/atom.xml" rel="self"/>
<link href="http://example.com/"/>
<updated>2024-09-16T08:46:44.934Z</updated>
<id>http://example.com/</id>
<author>
<name>Jinming Zhang</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>电子游戏为何让我们感到快乐</title>
<link href="http://example.com/2024/09/16/game/fun/"/>
<id>http://example.com/2024/09/16/game/fun/</id>
<published>2024-09-16T08:18:14.000Z</published>
<updated>2024-09-16T08:46:44.934Z</updated>
<content type="html"><![CDATA[<h2 id="我们为什么需要游戏"><a href="#我们为什么需要游戏" class="headerlink" title="我们为什么需要游戏"></a>我们为什么需要游戏</h2><p>游戏行为,其实是一个非常普遍的现象,它并不局限于人类个体。动物行为学领域有一个专门的研究分支,就是游戏行为。许多哺乳动物都有游戏行为,猫会扑咬同伴,狗会嘻戏打闹,丰富的游戏行为使得这些动物幼崽更好地提前适应自然界,在这些游戏中学到的生存技能决定了他们的命运。<br>人类也是如此,天生热爱游戏。可以回想一下,童年时期的那些游戏,捉迷藏、跳房子,为什么会那么强烈地吸引着我们。这些游戏,可以拆解成创造问题和解决问题的过程。就捉迷藏而言,它先是将参与者分为两个阵营,尽力隐藏自身的人,与尽力发现人类的鬼,对人而言,游戏带来的问题就是,如何隐藏自身并在不被鬼发现的情况下抵达终点;对鬼而言,它要解决的问题就是,如何尽快寻获隐藏起来的人类。在游戏进程中,双方的位置在不断发生变化,他们均需要通过对方的脚步声判断敌方走向,从而调整自身的位置,这便是游戏中的内循环。整个游戏过程充满刺激,隐藏自身与发现猎物,是人类数百万年发展历史中永远的循环,而捉迷藏这个游戏,则是这个循环的缩影。</p>]]></content>
<summary type="html"><h2 id="我们为什么需要游戏"><a href="#我们为什么需要游戏" class="headerlink"</summary>
<category term="-- game" scheme="http://example.com/tags/game/"/>
</entry>
<entry>
<title>火焰纹章Engage分析</title>
<link href="http://example.com/2024/09/16/game/tbs/fe/engage/"/>
<id>http://example.com/2024/09/16/game/tbs/fe/engage/</id>
<published>2024-09-16T07:50:38.000Z</published>
<updated>2024-09-16T08:17:32.675Z</updated>
<content type="html"><![CDATA[<h2 id="本作特点"><a href="#本作特点" class="headerlink" title="本作特点"></a>本作特点</h2><p> Engage为火纹系列第18部正传,作为风花雪月的后继者,Engage取消了前作的学园系统,削弱了社交因素,取消了多线叙事,回归了纯粹的回合制策略游戏玩法。作为一款SRPG,Engage的策略玩法毫无疑问是很优秀的,但是也因为其故事背景的过于老套以及人物刻画的不足而饱受诟病。</p>]]></content>
<summary type="html"><h2 id="本作特点"><a href="#本作特点" class="headerlink" title="本作特点"></a>本作特点</h2><p> </summary>
<category term="game" scheme="http://example.com/tags/game/"/>
<category term="tbs" scheme="http://example.com/tags/tbs/"/>
<category term="fire emblem" scheme="http://example.com/tags/fire-emblem/"/>
</entry>
<entry>
<title>大端序与小端序的优缺点比较</title>
<link href="http://example.com/2024/04/09/littlebigendian/"/>
<id>http://example.com/2024/04/09/littlebigendian/</id>
<published>2024-04-09T10:12:04.000Z</published>
<updated>2024-04-09T10:35:59.895Z</updated>
<content type="html"><![CDATA[<h2 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h2><p>高位数据在低位字节叫大端序,反之叫小端序</p><h2 id="大端序占优的场景"><a href="#大端序占优的场景" class="headerlink" title="大端序占优的场景"></a>大端序占优的场景</h2><ol><li>检查正负号</li></ol><p>这个很容易得知,大端序只要判断第一位是不是负号就行了。</p><h2 id="小端序占优的场景"><a href="#小端序占优的场景" class="headerlink" title="小端序占优的场景"></a>小端序占优的场景</h2><ol><li>判断奇偶性</li></ol><p>小端序数据的最后一位在最低位地址,判断奇偶性占优势。</p><ol start="2"><li>判断大小</li></ol><p>小端序数据已经按位对齐了,比较大小时占优势</p><ol start="3"><li>乘法</li></ol><p>小端序数据进行乘法时,每一位数据算出后可以直接写入内存,相比大端序具有明显优势。大端序的低位字节要存储的数据必须等到后面的位全部算出来了才能确定,小端序直接就可以确定。</p><p><img src="/image-1.png" alt="alt text"></p><ol start="4"><li>任意精度整数</li></ol><p>又称为大整数,其内部实现通常是把一个很大的数内部分成许多u64数据,小端序因为从左向右进位,每次只需要读取一个u64就可以计算,大端序就需要读取整个数据才能开始计算。</p><ol start="5"><li>强制类型转换</li></ol><p>比如把32位数转换成16位,小端序直接删掉后面2个字节就好了</p><p>网络字节序用的是大端序,TCP/IP规定发送的一个字节为高位字节,主机字节序通常是小端序,小端序有利于计算,大端序更符合人类的阅读习惯。</p>]]></content>
<summary type="html">本文探讨了大端序和小端序的优缺点以及应用场景</summary>
<category term="basic" scheme="http://example.com/tags/basic/"/>
</entry>
<entry>
<title>C++中的菱形继承问题</title>
<link href="http://example.com/2024/04/08/C-%E4%B8%AD%E7%9A%84%E8%8F%B1%E5%BD%A2%E7%BB%A7%E6%89%BF%E9%97%AE%E9%A2%98/"/>
<id>http://example.com/2024/04/08/C-%E4%B8%AD%E7%9A%84%E8%8F%B1%E5%BD%A2%E7%BB%A7%E6%89%BF%E9%97%AE%E9%A2%98/</id>
<published>2024-04-08T12:09:46.000Z</published>
<updated>2024-04-08T12:20:01.209Z</updated>
<content type="html"><![CDATA[<h2 id="什么是菱形继承"><a href="#什么是菱形继承" class="headerlink" title="什么是菱形继承"></a>什么是菱形继承</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">grandfather</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-type">int</span> age;<br> <span class="hljs-built_in">grandfather</span>() {<br> age = <span class="hljs-number">108</span>;<br> }<br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">father1</span>: <span class="hljs-keyword">public</span> grandfather{};<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">father2</span>: <span class="hljs-keyword">public</span> grandfather{};<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">son</span> :<span class="hljs-keyword">public</span> father1, <span class="hljs-keyword">public</span> father2{};<br></code></pre></td></tr></table></figure><p>这时son就是菱形继承的产物,如果编写以下代码</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> son s;<br> s.age=<span class="hljs-number">4</span>;<br> cout<<s.age;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><p>甚至无法通过编译</p><p><img src="/image.png" alt="alt text"></p><h2 id="如何解决"><a href="#如何解决" class="headerlink" title="如何解决"></a>如何解决</h2><ol><li>手动写明作用域</li><li>使用virtual public 继承</li></ol><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> son s;<br> s.father1::age = <span class="hljs-number">4</span>;<br> cout << s.father1::age;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br>```cpp<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">father1</span>:<span class="hljs-keyword">virtual</span> <span class="hljs-keyword">public</span> grandfather{};<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">father2</span>:<span class="hljs-keyword">virtual</span> <span class="hljs-keyword">public</span> grandfather{};<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">son</span> :<span class="hljs-keyword">public</span> father1, <span class="hljs-keyword">public</span> father2{};<br></code></pre></td></tr></table></figure><p>以上两种方式均可以通过编译,但是使用第二种方式的话,p.age, p.father1::age, p.father2::age其实会指向同一块内存区域,既浪费了空间(多了两个vbptr),又没起到任何作用,所以还是要尽量避免菱形继承的使用。</p>]]></content>
<summary type="html">本文探讨如何解决菱形继承带来的问题</summary>
<category term="cpp" scheme="http://example.com/tags/cpp/"/>
</entry>
<entry>
<title>C++中的仿函数</title>
<link href="http://example.com/2024/04/08/C-%E4%B8%AD%E7%9A%84%E4%BB%BF%E5%87%BD%E6%95%B0/"/>
<id>http://example.com/2024/04/08/C-%E4%B8%AD%E7%9A%84%E4%BB%BF%E5%87%BD%E6%95%B0/</id>
<published>2024-04-08T11:13:42.000Z</published>
<updated>2024-04-08T12:06:05.572Z</updated>
<content type="html"><![CDATA[<h2 id="仿函数是什么"><a href="#仿函数是什么" class="headerlink" title="仿函数是什么"></a>仿函数是什么</h2><p>仿函数(Functor)在C++中和函数对象是一个概念,它们都是重载了函数调用运算符的类的对象,Functor是STL六大模块之一,其余模块分别是Container, Algorithm, Iterator, Adaptor, Allocator.</p><h2 id="仿函数存在的意义"><a href="#仿函数存在的意义" class="headerlink" title="仿函数存在的意义"></a>仿函数存在的意义</h2><p>仿函数的作用和C语言中的函数指针很像,但它扩展性更好。当我们需要为某种算法提供特定“操作”(比如说排序方式)时,我们可以传入函数指针,但如果将来这个函数的签名(参数个数,参数类型,参数顺序,不包括返回值类型)发生了变化,就需要做很大调整了。其次,函数之间可能会共用变量,维护全局变量也很麻烦。仿函数就没有这些缺点,它可以被依赖、组合和继承,在自己的类中维护变量,功能更加强大。</p><p>比如在用到unordered_map或者unordered_set的时候,我们可能会需要将自定义类用作key,这时我们需要做两件事</p><ol><li>为这个类重载等于运算符</li><li>提供用于hash的仿函数</li></ol><p>举个例子,对于下面这个磁盘页面类</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">struct</span> <span class="hljs-title class_">PageId</span> {<br> <span class="hljs-type">int</span> fd;<br> <span class="hljs-type">page_id_t</span> page_no = INVALID_PAGE_ID;<br> <span class="hljs-keyword">friend</span> <span class="hljs-type">bool</span> <span class="hljs-keyword">operator</span>==(<span class="hljs-type">const</span> PageId& x, <span class="hljs-type">const</span> PageId& y) {<br> <span class="hljs-keyword">return</span> x.fd==y.fd&&x.page_no==y.page_no;<br> }<br> <span class="hljs-type">bool</span> <span class="hljs-keyword">operator</span><(<span class="hljs-type">const</span> PageId &x) <span class="hljs-type">const</span> {<br> <span class="hljs-keyword">if</span> (fd < x.fd)<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> <span class="hljs-keyword">return</span> page_no < x.page_no;<br> }<br> <span class="hljs-function">std::string <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-string">"{fd: "</span> + std::<span class="hljs-built_in">to_string</span>(fd) +<br> <span class="hljs-string">" page_no: "</span> + std::<span class="hljs-built_in">to_string</span>(page_no) + <span class="hljs-string">"}"</span>;<br> }<br> <span class="hljs-function"><span class="hljs-keyword">inline</span> <span class="hljs-type">int64_t</span> <span class="hljs-title">Get</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>{<br> <span class="hljs-keyword">return</span> (<span class="hljs-built_in">static_cast</span><<span class="hljs-type">int64_t</span>>(fd << <span class="hljs-number">16</span>) | page_no);<br> }<br>};<br></code></pre></td></tr></table></figure><p>我们需要提供一个hash函数对象,从而构建一个unordered_map,使得磁盘中的页和内存中的帧可以一一对应</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">struct</span> <span class="hljs-title class_">PageIdHash</span> {<br> <span class="hljs-function"><span class="hljs-type">size_t</span> <span class="hljs-title">operator</span><span class="hljs-params">()</span><span class="hljs-params">(<span class="hljs-type">const</span> PageId &x)</span> <span class="hljs-type">const</span> </span>{ <span class="hljs-keyword">return</span> (x.fd << <span class="hljs-number">16</span>) | x.page_no; }<br>};<br></code></pre></td></tr></table></figure><p>这样我们就可以获得std::unordered_map<PageId,frame_id_t,PageIdHash>了,如果我们想要提供默认实现,可以<br>再使用模板特化的方法</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">template</span> <> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">std</span>::hash<PageId> {<br> <span class="hljs-function"><span class="hljs-type">size_t</span> <span class="hljs-title">operator</span><span class="hljs-params">()</span><span class="hljs-params">(<span class="hljs-type">const</span> PageId &obj)</span> <span class="hljs-type">const</span> </span>{<br> <span class="hljs-keyword">return</span> std::<span class="hljs-built_in">hash</span><<span class="hljs-type">int64_t</span>>()(obj.<span class="hljs-built_in">Get</span>());<br> }<br>};<br></code></pre></td></tr></table></figure><p>有时候仿函数的存在是为了让函数具有类的性质,通过仿函数,我们可以在拥有函数功能的同时,拥有状态,依据函数生成对象,让函数能彼此继承。仿函数主要在STl中使用,lambda的内部实现也是用的仿函数。</p>]]></content>
<summary type="html">本文讨论了C++中functor的作用和特点</summary>
<category term="cpp" scheme="http://example.com/tags/cpp/"/>
</entry>
<entry>
<title>struct和class的本质区别</title>
<link href="http://example.com/2024/01/02/struct%E5%92%8Cclas%E7%9A%84%E6%9C%AC%E8%B4%A8%E5%8C%BA%E5%88%AB/"/>
<id>http://example.com/2024/01/02/struct%E5%92%8Cclas%E7%9A%84%E6%9C%AC%E8%B4%A8%E5%8C%BA%E5%88%AB/</id>
<published>2024-01-02T13:21:24.000Z</published>
<updated>2024-04-19T04:16:38.800Z</updated>
<content type="html"><![CDATA[<h2 id="本质区别"><a href="#本质区别" class="headerlink" title="本质区别"></a>本质区别</h2><p>struct是值类型,而class是引用类型。值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。引用类型的对象总是在进程堆中分配(动态分配)。虽然堆栈的执行效率要比堆的高,但是堆栈资源却很有限,不适合处理逻辑复杂的大对象,因此struct常用来处理作为基类型对待的小对象,用class来处理更复杂的商业逻辑。</p><h2 id="其他的使用上的区别"><a href="#其他的使用上的区别" class="headerlink" title="其他的使用上的区别"></a>其他的使用上的区别</h2><ol><li>struct字段和继承方式默认public,class则是private</li><li>结构体存储自身的数据,class仅存储一个动态对象的引用</li><li>C语言中struct不可以为空,但是C++中可以</li></ol>]]></content>
<summary type="html"><h2 id="本质区别"><a href="#本质区别" class="headerlink"</summary>
<category term="cpp" scheme="http://example.com/tags/cpp/"/>
</entry>
<entry>
<title>shared_ptr的简易实现</title>
<link href="http://example.com/2023/08/11/shared-ptr%E7%9A%84%E7%AE%80%E6%98%93%E5%AE%9E%E7%8E%B0/"/>
<id>http://example.com/2023/08/11/shared-ptr%E7%9A%84%E7%AE%80%E6%98%93%E5%AE%9E%E7%8E%B0/</id>
<published>2023-08-11T04:56:32.000Z</published>
<updated>2024-04-18T01:16:04.577Z</updated>
<content type="html"><![CDATA[<h2 id="实现一个简易shared-ptr模板类需要些什么"><a href="#实现一个简易shared-ptr模板类需要些什么" class="headerlink" title="实现一个简易shared_ptr模板类需要些什么"></a>实现一个简易shared_ptr模板类需要些什么</h2><ol><li>引用计数</li><li>控制对引用计数访问权限的互斥锁</li><li>构造函数,拷贝构造函数,重载赋值运算符,解引用运算符等等</li><li>析构函数,避免在临界区访问引用计数</li></ol><h2 id="类的私有成员变量"><a href="#类的私有成员变量" class="headerlink" title="类的私有成员变量"></a>类的私有成员变量</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">template</span><<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>> <br><span class="hljs-keyword">class</span> <span class="hljs-title class_">my_shared_ptr</span>{<br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">int</span>* _p_ref_count;<br> std::mutex* _p_mutex;<br> T* _p_ptr;<br>}; <br></code></pre></td></tr></table></figure><h2 id="定义构造与析构函数"><a href="#定义构造与析构函数" class="headerlink" title="定义构造与析构函数"></a>定义构造与析构函数</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">template</span><<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">my_shared_ptr</span>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">my_shared_ptr</span>(T* ptr=<span class="hljs-literal">nullptr</span>): <br> _p_ref_count(<span class="hljs-keyword">new</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">1</span>)),<br> _p_mutex(<span class="hljs-keyword">new</span> std::mutex),<br> _p_ptr(ptr) {}<br> <span class="hljs-built_in">my_shared_ptr</span>(<span class="hljs-type">const</span> my_shared_ptr<T>& msp)<br> _p_ref_count(msp._p_ref_count),<br> _p_mutex(msp._p_mutex),<br> _p_ptr(msp._p_ptr) {<br> <span class="hljs-built_in">add_ref_count</span>();<br> }<br> ~<span class="hljs-built_in">my_shared_ptr</span>() {<br> <span class="hljs-built_in">release</span>();<br> }<br> my_shared_ptr<T>& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> my_shared_ptr<T>& msp) {<br> <span class="hljs-keyword">if</span>(_p_ptr!=msp._p_ptr) {<br> <span class="hljs-built_in">release</span>(); <span class="hljs-comment">// 释放旧资源</span><br> _p_ref_count = msp._p_ref_count;<br> _p_mutex = msp._p_mutex;<br> _p_ptr = msp._p_ptr;<br> <span class="hljs-built_in">add_ref_count</span>();<br> }<br> <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;<br> }<br> T& <span class="hljs-keyword">operator</span>*() {<br> <span class="hljs-keyword">return</span> *_p_ptr;<br> }<br> T* <span class="hljs-keyword">operator</span>->() {<br> <span class="hljs-keyword">return</span> _p_ptr;<br> }<br> <span class="hljs-function">T* <span class="hljs-title">get</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">return</span> _p_ptr;<br> }<br> <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">get_ref_count</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">return</span> *_p_ref_count;<br> }<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">add_ref_count</span><span class="hljs-params">()</span> </span>{<br> _p_mutex-><span class="hljs-built_in">lock</span>();<br> ++(*_p_ref_count);<br> _p_mutex-><span class="hljs-built_in">unlock</span>();<br> }<br><span class="hljs-keyword">private</span>:<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">release</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-type">bool</span> delete_flag = <span class="hljs-literal">false</span>;<br> _p_mutex-><span class="hljs-built_in">lock</span>();<br> <span class="hljs-keyword">if</span>(--(*_p_ref_count)==<span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">delete</span> _p_ref_count;<br> <span class="hljs-keyword">delete</span> _p_ptr;<br> delete_flag = <span class="hljs-literal">true</span>;<br> }<br> _p_mutex-><span class="hljs-built_in">unlock</span>();<br> <span class="hljs-keyword">if</span>(delete_flag) <span class="hljs-keyword">delete</span> _p_mutex;<br> }<br>};<br></code></pre></td></tr></table></figure><h2 id="线程安全问题"><a href="#线程安全问题" class="headerlink" title="线程安全问题"></a>线程安全问题</h2><ol><li>my_shared_ptr对象中的引用计数因为使用了互斥锁所以是线程安全的</li><li>但是my_shared_ptr管理的对象存放在堆上,如果两个线程同时访问,则将造成线程安全问题</li></ol><h2 id="存在的问题"><a href="#存在的问题" class="headerlink" title="存在的问题"></a>存在的问题</h2><p>my_shared_ptr模板类没有考虑不是new出来的对象,实际上shared_ptr针对这种情况设计了仿函数删除器</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// 仿函数的删除器</span><br><span class="hljs-keyword">template</span><<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>><br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">FreeFunc</span> {<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">operator</span><span class="hljs-params">()</span><span class="hljs-params">(T* ptr)</span> </span>{<br> cout << <span class="hljs-string">"free:"</span> << ptr << endl;<br> <span class="hljs-built_in">free</span>(ptr);<br> }<br>};<br><span class="hljs-keyword">template</span><<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>><br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">DeleteArrayFunc</span> {<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">operator</span><span class="hljs-params">()</span><span class="hljs-params">(T* ptr)</span> </span>{<br> cout << <span class="hljs-string">"delete[]"</span> << ptr << endl;<br> <span class="hljs-keyword">delete</span>[] ptr;<br> }<br>};<br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{ <br> FreeFunc<<span class="hljs-type">int</span>> freeFunc;<br> <span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">sp1</span><span class="hljs-params">((<span class="hljs-type">int</span>*)malloc(<span class="hljs-number">4</span>), freeFunc)</span></span>;<br> DeleteArrayFunc<<span class="hljs-type">int</span>> deleteArrayFunc;<br> <span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">sp2</span><span class="hljs-params">((<span class="hljs-type">int</span>*)malloc(<span class="hljs-number">4</span>), deleteArrayFunc)</span></span>;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h2 id="std-shared-ptr的线程安全问题"><a href="#std-shared-ptr的线程安全问题" class="headerlink" title="std::shared_ptr的线程安全问题"></a>std::shared_ptr的线程安全问题</h2><h3 id="在哪些方面存在安全隐患"><a href="#在哪些方面存在安全隐患" class="headerlink" title="在哪些方面存在安全隐患"></a>在哪些方面存在安全隐患</h3><ol><li>引用计数</li><li>修改指向</li><li>shared_ptr<T>中的T的线程安全问题</li></ol><p>std::shared_ptr中有两个指针,一个指向所管理的数据,一个指向控制块,这里面包括引用计数,weak_ptr的数量,删除器和分配器之类的,rc是存放在堆上的。</p><p>根据cppreference的说法,rc的加减是内存安全的</p><p><code>To satisfy thread safety requirements, the reference counters are typically incremented using an equivalent of std::atomic::fetch_add with std::memory_order_relaxed (decrementing requires stronger ordering to safely destroy the control block)</code></p><p>关于修改指向时的线程安全问题,依多线程访问的是不是同一个shared_ptr模板类的对象有所不同</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function">std::thread <span class="hljs-title">td</span><span class="hljs-params">([&sp1] () {....})</span></span>;<br>``<br><br>```<span class="hljs-function">cpp</span><br><span class="hljs-function">std::thread <span class="hljs-title">td</span><span class="hljs-params">([sp1] () {....})</span></span>;<br></code></pre></td></tr></table></figure><p>如果std::thread的回调函数是一个lambda表达式,那么如果这里是引用捕获就有问题,拷贝就没事</p><p>或者下面这种</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fn</span><span class="hljs-params">(shared_ptr<A>* sp)</span> </span>{<br> ...<br>}<br>...<br> <span class="hljs-function">std::thread <span class="hljs-title">td</span><span class="hljs-params">(fn, &sp1)</span></span>;<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fn</span><span class="hljs-params">(shared_ptr<A>& sp)</span> </span>{<br> ...<br>}<br>...<br> <span class="hljs-function">std::thread <span class="hljs-title">td</span><span class="hljs-params">(fn, std::ref(sp1))</span></span>;<br></code></pre></td></tr></table></figure><p>当我们在多线程回调中修改指向时,就不是线程安全的了</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fn</span><span class="hljs-params">(shared_ptr<A>& sp)</span> </span>{<br> ...<br> <span class="hljs-keyword">if</span> (..) {<br> sp = other_sp;<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (...) {<br> sp = other_sp2;<br> }<br>}<br></code></pre></td></tr></table></figure><p>这时other_sp的rc要加1,sp的要减1,但这整个过程并不是一个原子过程</p><p>最后,如果shared_str管理的数据是STL容器这类,那么任何多线程间修改容器结构的操作都很容易导致core dump.</p><h2 id="unique-ptr的简易实现"><a href="#unique-ptr的简易实现" class="headerlink" title="unique_ptr的简易实现"></a>unique_ptr的简易实现</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">template</span><<span class="hljs-keyword">typename</span> T><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyUniquePtr</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">MyUniquePtr</span><span class="hljs-params">(T* ptr = <span class="hljs-literal">nullptr</span>)</span></span><br><span class="hljs-function"> :mPtr(ptr)</span><br><span class="hljs-function"> {</span>}<br><br> ~<span class="hljs-built_in">MyUniquePtr</span>()<br> {<br> <span class="hljs-keyword">if</span>(mPtr)<br> <span class="hljs-keyword">delete</span> mPtr;<br> }<br><br> <span class="hljs-built_in">MyUniquePtr</span>(MyUniquePtr &&p) <span class="hljs-keyword">noexcept</span>;<br> MyUniquePtr& <span class="hljs-keyword">operator</span>=(MyUniquePtr &&p) <span class="hljs-keyword">noexcept</span>;<br><br> <span class="hljs-built_in">MyUniquePtr</span>(<span class="hljs-type">const</span> MyUniquePtr &p) = <span class="hljs-keyword">delete</span>;<br> MyUniquePtr& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> MyUniquePtr &p) = <span class="hljs-keyword">delete</span>;<br><br> T& <span class="hljs-keyword">operator</span>*() <span class="hljs-type">const</span> <span class="hljs-keyword">noexcept</span> {<span class="hljs-keyword">return</span> *mPtr;}<br> T* <span class="hljs-keyword">operator</span>->()<span class="hljs-type">const</span> <span class="hljs-keyword">noexcept</span> {<span class="hljs-keyword">return</span> mPtr;}<br> <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-keyword">operator</span> <span class="hljs-title">bool</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> <span class="hljs-keyword">noexcept</span></span>{<span class="hljs-keyword">return</span> mPtr;}<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">reset</span><span class="hljs-params">(T* q = <span class="hljs-literal">nullptr</span>)</span> <span class="hljs-keyword">noexcept</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">if</span>(q != mPtr){<br> <span class="hljs-keyword">if</span>(mPtr)<br> <span class="hljs-keyword">delete</span> mPtr;<br> mPtr = q;<br> }<br> }<br><br> <span class="hljs-function">T* <span class="hljs-title">release</span><span class="hljs-params">()</span> <span class="hljs-keyword">noexcept</span></span><br><span class="hljs-function"> </span>{<br> T* res = mPtr;<br> mPtr = <span class="hljs-literal">nullptr</span>;<br> <span class="hljs-keyword">return</span> res;<br> }<br> <span class="hljs-function">T* <span class="hljs-title">get</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> <span class="hljs-keyword">noexcept</span> </span>{<span class="hljs-keyword">return</span> mPtr;}<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">swap</span><span class="hljs-params">(MyUniquePtr &p)</span> <span class="hljs-keyword">noexcept</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">using</span> std::swap;<br> <span class="hljs-built_in">swap</span>(mPtr, p.mPtr);<br> }<br><span class="hljs-keyword">private</span>:<br> T* mPtr;<br>};<br><br><span class="hljs-keyword">template</span><<span class="hljs-keyword">typename</span> T><br>MyUniquePtr<T>& MyUniquePtr<T>::<span class="hljs-keyword">operator</span>=(MyUniquePtr &&p) <span class="hljs-keyword">noexcept</span><br>{<br> <span class="hljs-built_in">swap</span>(*<span class="hljs-keyword">this</span>, p);<br> <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;<br>}<br><br><span class="hljs-keyword">template</span><<span class="hljs-keyword">typename</span> T><br>MyUniquePtr<T> :: <span class="hljs-built_in">MyUniquePtr</span>(MyUniquePtr &&p) <span class="hljs-keyword">noexcept</span> : <span class="hljs-built_in">mPtr</span>(p.mPtr)<br>{<br> p.mPtr == <span class="hljs-literal">NULL</span>;<br>}<br></code></pre></td></tr></table></figure><p>要注意bool运算符要是explicit的,不然判断ptr1==ptr2的时候,就会把两边都转化为bool值true,另外就是赋值运算符,用swap,因为自赋值情况是很少见的,用swap的话,不是自赋值的时候,另一个指针超出作用域会被自动析构,这样效率更高</p>]]></content>
<summary type="html">自己动手实现my_shared_ptr模板类</summary>
<category term="cpp" scheme="http://example.com/tags/cpp/"/>
</entry>
<entry>
<title>tcp粘包问题的成因与解决方案</title>
<link href="http://example.com/2023/07/08/tcp%E7%B2%98%E5%8C%85%E9%97%AE%E9%A2%98%E7%9A%84%E6%88%90%E5%9B%A0%E4%B8%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
<id>http://example.com/2023/07/08/tcp%E7%B2%98%E5%8C%85%E9%97%AE%E9%A2%98%E7%9A%84%E6%88%90%E5%9B%A0%E4%B8%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</id>
<published>2023-07-08T01:56:40.000Z</published>
<updated>2024-04-01T06:16:44.390Z</updated>
<content type="html"><![CDATA[<h2 id="TCP粘包问题是什么"><a href="#TCP粘包问题是什么" class="headerlink" title="TCP粘包问题是什么"></a>TCP粘包问题是什么</h2><p>TCP粘包问题指的是发送方发送的若干数据包在到达接收方时粘成了一包</p><h2 id="造成粘包问题的可能原因"><a href="#造成粘包问题的可能原因" class="headerlink" title="造成粘包问题的可能原因"></a>造成粘包问题的可能原因</h2><h3 id="接收方"><a href="#接收方" class="headerlink" title="接收方"></a>接收方</h3><p>TCP接收端接收到数据包时,并不会直接交给应用程序处理,而是会先放到缓存中,如果应用程序从缓存中读取数据包的速度<br>小于TCP将接收到的数据包放到缓存中的速度,多个数据包在缓存中就有可能首尾相连</p><h3 id="发送方"><a href="#发送方" class="headerlink" title="发送方"></a>发送方</h3><p>使用了Nagle算法,在收到一次确认时,才会发送下一个分组,并且这个分组是多个小分组的集合体</p><h2 id="一定要解决粘包问题吗"><a href="#一定要解决粘包问题吗" class="headerlink" title="一定要解决粘包问题吗"></a>一定要解决粘包问题吗</h2><p>不一定,如果这些数据包本来就是同一块数据的不同部分,那么没必要处理;如果是多个并列的,或者是多个互不相关的分组<br>,那就必须要处理了</p><h2 id="如何解决"><a href="#如何解决" class="headerlink" title="如何解决"></a>如何解决</h2><ol><li>发送方: 可以使用TCP_NODELAY选项关闭NAGLE算法</li><li>应用层:格式化数据,使得每条数据有固定的格式(开始符,结束符),并在发送时一并发送数据长度,这样接收方应用程序就能轻松读取数据包长度,方便循环处理</li></ol><h2 id="UDP会出现粘包问题吗"><a href="#UDP会出现粘包问题吗" class="headerlink" title="UDP会出现粘包问题吗"></a>UDP会出现粘包问题吗</h2><p>不会,UDP协议面向数据报,TCP协议面向流,UDP保护消息边界,TCP不保护,所以TCP会出现粘包问题,UDP不会 </p>]]></content>
<summary type="html">本文探讨了因Nagle算法导致的tcp粘包问题</summary>
<category term="network" scheme="http://example.com/tags/network/"/>
</entry>
</feed>