@@ -155,45 +155,89 @@ <h1 class="menu-title"></h1>
155
155
156
156
< div id ="content " class ="content ">
157
157
< main >
158
- < h1 > < a class ="header " href ="#exception-safety " id ="exception-safety "> Exception Safety</ a > </ h1 >
159
- < p > Although programs should use unwinding sparingly, there's a lot of code that
160
- < em > can</ em > panic. If you unwrap a None, index out of bounds, or divide by 0, your
158
+ <!--
159
+ # Exception Safety
160
+ -->
161
+ < h1 > < a class ="header " href ="#例外安全性 " id ="例外安全性 "> 例外安全性</ a > </ h1 >
162
+ <!--
163
+ Although programs should use unwinding sparingly, there's a lot of code that
164
+ *can* panic. If you unwrap a None, index out of bounds, or divide by 0, your
161
165
program will panic. On debug builds, every arithmetic operation can panic
162
166
if it overflows. Unless you are very careful and tightly control what code runs,
163
- pretty much everything can unwind, and you need to be ready for it.</ p >
164
- < p > Being ready for unwinding is often referred to as < em > exception safety</ em >
167
+ pretty much everything can unwind, and you need to be ready for it.
168
+ -->
169
+ < p > プログラム内では巻き戻しを注意深く使用するべきですが、パニック< em > し得る</ em > コードが
170
+ たくさんあります。もし None をアンラップしたり、境界外のインデックスを指定したり、
171
+ 0 で除算したりしたら、プログラムはパニックするでしょう。デバッグビルドでは、
172
+ 全ての算術演算は、オーバーフロー時にパニックします。非常に注意深く、
173
+ そしてどのコードを実行するかを厳しくコントロールしない限り、ほとんどすべての
174
+ コードが巻き戻しをする可能性があり、これに対して準備をする必要があります。</ p >
175
+ <!--
176
+ Being ready for unwinding is often referred to as *exception safety*
165
177
in the broader programming world. In Rust, there are two levels of exception
166
- safety that one may concern themselves with:</ p >
178
+ safety that one may concern themselves with:
179
+ -->
180
+ < p > 巻き戻しに対して準備が出来ていることは、もっと広いプログラミングの世界において、
181
+ しばしば< em > 例外安全</ em > と呼ばれています。 Rust では、プログラムが関わる可能性のある、
182
+ 2 つの例外安全のレベルがあります。</ p >
183
+ <!--
184
+ * In unsafe code, we *must* be exception safe to the point of not violating
185
+ memory safety. We'll call this *minimal* exception safety.
186
+
187
+ * In safe code, it is *good* to be exception safe to the point of your program
188
+ doing the right thing. We'll call this *maximal* exception safety.
189
+ -->
167
190
< ul >
168
191
< li >
169
- < p > In unsafe code, we < em > must </ em > be exception safe to the point of not violating
170
- memory safety. We'll call this < em > minimal </ em > exception safety. </ p >
192
+ < p > アンセーフなコードでは、メモリ安全性を侵害しないという点において、
193
+ 例外安全で < em > なければなりません </ em > 。これを、 < em > 最小限 </ em > の例外安全と呼びます。 </ p >
171
194
</ li >
172
195
< li >
173
- < p > In safe code, it is < em > good </ em > to be exception safe to the point of your program
174
- doing the right thing. We'll call this < em > maximal </ em > exception safety. </ p >
196
+ < p > 安全なコードでは、プログラムが正しいことを行なうという点において、
197
+ 例外安全であると < em > 良い </ em > です。これを < em > 最大限 </ em > の例外安全と呼びます。 </ p >
175
198
</ li >
176
199
</ ul >
177
- < p > As is the case in many places in Rust, Unsafe code must be ready to deal with
200
+ <!--
201
+ As is the case in many places in Rust, Unsafe code must be ready to deal with
178
202
bad Safe code when it comes to unwinding. Code that transiently creates
179
203
unsound states must be careful that a panic does not cause that state to be
180
204
used. Generally this means ensuring that only non-panicking code is run while
181
205
these states exist, or making a guard that cleans up the state in the case of
182
206
a panic. This does not necessarily mean that the state a panic witnesses is a
183
- fully coherent state. We need only guarantee that it's a < em > safe</ em > state.</ p >
184
- < p > Most Unsafe code is leaf-like, and therefore fairly easy to make exception-safe.
207
+ fully coherent state. We need only guarantee that it's a *safe* state.
208
+ -->
209
+ < p > Rust の多くの場において事実なのですが、巻き戻しとなると、アンセーフなコードは、
210
+ 悪い安全なコードに対処する準備をしなければなりません。一時的に健全ではない
211
+ 状態を生むコードは、パニックによってその状態が使用されないよう、注意深く
212
+ 扱わなければなりません。通常これは、このような健全でない状態が存在する間、
213
+ パニックを起こさないコードのみを確実に実行させることを意味するか、あるいは
214
+ パニックの際、その状態を片付けるガードを生成することを意味します。
215
+ これは必ずしも、パニックが起きているときの状態が、完全に一貫した状態であるということを
216
+ 意味しません。< em > 安全な</ em > 状態であると保証されていることだけが必要なのです。</ p >
217
+ <!--
218
+ Most Unsafe code is leaf-like, and therefore fairly easy to make exception-safe.
185
219
It controls all the code that runs, and most of that code can't panic. However
186
220
it is not uncommon for Unsafe code to work with arrays of temporarily
187
221
uninitialized data while repeatedly invoking caller-provided code. Such code
188
- needs to be careful and consider exception safety.</ p >
222
+ needs to be careful and consider exception safety.
223
+ -->
224
+ < p > ほとんどのアンセーフなコードは葉のようなもの (訳注: それ以上別の関数を呼ぶことが
225
+ ない) で、それ故に割と簡単に例外安全に出来ます。実行するコードは完全に制御されていて、
226
+ そしてほとんどのコードはパニックしません。しかし、アンセーフなコードが
227
+ 繰り返し呼び出し側のコードを実行している間に、部分的に初期化されていない配列を
228
+ 扱うことはよくあります。このようなコードは注意深く扱い、例外安全を考える必要があるのです。</ p >
189
229
< h2 > < a class ="header " href ="#vecpush_all " id ="vecpush_all "> Vec::push_all</ a > </ h2 >
190
- < p > < code > Vec::push_all</ code > is a temporary hack to get extending a Vec by a slice reliably
191
- efficient without specialization. Here's a simple implementation:</ p >
230
+ <!--
231
+ `Vec::push_all` is a temporary hack to get extending a Vec by a slice reliably
232
+ efficient without specialization. Here's a simple implementation:
233
+ -->
234
+ < p > < code > Vec::push_all</ code > は、特殊化なしに、スライスが確実に効率的であることを利用した、
235
+ Vec を伸ばす一時的なハックです。これは単純な実装です。</ p >
192
236
< pre > < code class ="language-rust ignore "> impl<T: Clone> Vec<T> {
193
237
fn push_all(&mut self, to_push: &[T]) {
194
238
self.reserve(to_push.len());
195
239
unsafe {
196
- // can't overflow because we just reserved this
240
+ // 今さっき reserve をしたので、オーバーフローするはずがありません
197
241
self.set_len(self.len() + to_push.len());
198
242
199
243
for (i, x) in to_push.iter().enumerate() {
@@ -203,44 +247,83 @@ <h2><a class="header" href="#vecpush_all" id="vecpush_all">Vec::push_all</a></h2
203
247
}
204
248
}
205
249
</ code > </ pre >
206
- < p > We bypass < code > push</ code > in order to avoid redundant capacity and < code > len</ code > checks on the
250
+ <!--
251
+ We bypass `push` in order to avoid redundant capacity and `len` checks on the
207
252
Vec that we definitely know has capacity. The logic is totally correct, except
208
- there's a subtle problem with our code: it's not exception-safe! < code > set_len</ code > ,
209
- < code > offset</ code > , and < code > write</ code > are all fine; < code > clone</ code > is the panic bomb we over-looked.</ p >
210
- < p > Clone is completely out of our control, and is totally free to panic. If it
253
+ there's a subtle problem with our code: it's not exception-safe! `set_len`,
254
+ `offset`, and `write` are all fine; `clone` is the panic bomb we over-looked.
255
+ -->
256
+ < p > 絶対にキャパシティがあると分かっている Vec の capacity と < code > len</ code > の余分なチェックを
257
+ 回避するため、 < code > push</ code > を使用していません。論理は完全に正しいです。但し、
258
+ このコードに微妙な問題が含まれていることを除く。すなわち、このコードは例外安全
259
+ ではないのです! < code > set_len</ code > と < code > offset</ code > と < code > write</ code > は全部問題ありません。 < code > clone</ code > は、
260
+ 我々が見落としていたパニックの起爆装置です。</ p >
261
+ <!--
262
+ Clone is completely out of our control, and is totally free to panic. If it
211
263
does, our function will exit early with the length of the Vec set too large. If
212
- the Vec is looked at or dropped, uninitialized memory will be read!</ p >
213
- < p > The fix in this case is fairly simple. If we want to guarantee that the values
214
- we < em > did</ em > clone are dropped, we can set the < code > len</ code > every loop iteration. If we
264
+ the Vec is looked at or dropped, uninitialized memory will be read!
265
+ -->
266
+ < p > Clone は全く制御不能で、全く自由にパニックしてしまいます。もしパニックしてしまえば、
267
+ この関数は、 Vec の長さが大きすぎる値に設定されたまま、早期に終了してしまいます。
268
+ もし Vec が読み出されたりドロップされたりすると、未初期化のメモリが読み出されて
269
+ しまいます!</ p >
270
+ <!--
271
+ The fix in this case is fairly simple. If we want to guarantee that the values
272
+ we *did* clone are dropped, we can set the `len` every loop iteration. If we
215
273
just want to guarantee that uninitialized memory can't be observed, we can set
216
- the < code > len</ code > after the loop.</ p >
274
+ the `len` after the loop.
275
+ -->
276
+ < p > この場合、修正は割と簡単です。もし< em > 本当に</ em > 、クローンした値がドロップされたと
277
+ いうことを保証したいのなら、全てのループのイテレーションにおいて、 < code > len</ code > を
278
+ 設定することが出来ます。もし単に、未初期化のメモリが読まれないようにしたいのなら、
279
+ ループの後に < code > len</ code > を設定することが出来ます。</ p >
217
280
< h2 > < a class ="header " href ="#binaryheapsift_up " id ="binaryheapsift_up "> BinaryHeap::sift_up</ a > </ h2 >
218
- < p > Bubbling an element up a heap is a bit more complicated than extending a Vec.
219
- The pseudocode is as follows:</ p >
281
+ <!--
282
+ Bubbling an element up a heap is a bit more complicated than extending a Vec.
283
+ The pseudocode is as follows:
284
+ -->
285
+ < p > ヒープにおけるアップヒープは Vec を伸ばすことよりちょっと複雑です。擬似コードはこんな感じです。</ p >
220
286
< pre > < code class ="language-text "> bubble_up(heap, index):
221
287
while index != 0 && heap[index] < heap[parent(index)]:
222
288
heap.swap(index, parent(index))
223
289
index = parent(index)
224
290
225
291
</ code > </ pre >
226
- < p > A literal transcription of this code to Rust is totally fine, but has an annoying
227
- performance characteristic: the < code > self</ code > element is swapped over and over again
228
- uselessly. We would rather have the following:</ p >
292
+ <!--
293
+ A literal transcription of this code to Rust is totally fine, but has an annoying
294
+ performance characteristic: the `self` element is swapped over and over again
295
+ uselessly. We would rather have the following:
296
+ -->
297
+ < p > このコードを Rust に直訳するのは全く問題ありません。ですが、嫌になるようなパフォーマンス
298
+ です。すなわち、 < code > self</ code > の要素が無駄に交換され続けます。それならむしろ、以下のコードの方が
299
+ 良いでしょう。</ p >
229
300
< pre > < code class ="language-text "> bubble_up(heap, index):
230
301
let elem = heap[index]
231
- while index != 0 && element < heap[parent(index)]:
302
+ while index != 0 && elem < heap[parent(index)]:
232
303
heap[index] = heap[parent(index)]
233
304
index = parent(index)
234
305
heap[index] = elem
235
306
</ code > </ pre >
236
- < p > This code ensures that each element is copied as little as possible (it is in
307
+ <!--
308
+ This code ensures that each element is copied as little as possible (it is in
237
309
fact necessary that elem be copied twice in general). However it now exposes
238
310
some exception safety trouble! At all times, there exists two copies of one
239
311
value. If we panic in this function something will be double-dropped.
240
312
Unfortunately, we also don't have full control of the code: that comparison is
241
- user-defined!</ p >
242
- < p > Unlike Vec, the fix isn't as easy here. One option is to break the user-defined
243
- code and the unsafe code into two separate phases:</ p >
313
+ user-defined!
314
+ -->
315
+ < p > このコードでは確実に、それぞれの要素ができるだけ少ない回数でコピーされます
316
+ (実は一般的に、要素を 2 回コピーすることが必要なのです) 。しかし、これによって、
317
+ いくつか例外安全性の問題が露見しました! 毎回、ある値に対する 2 つのコピーが
318
+ 存在します。もしこの関数内でパニックしたら、何かが 2 回ドロップされてしまいます。
319
+ 残念ながら、このコードに関しても、完全にコントロールすることは出来ません。
320
+ 比較がユーザ定義されているのです!</ p >
321
+ <!--
322
+ Unlike Vec, the fix isn't as easy here. One option is to break the user-defined
323
+ code and the unsafe code into two separate phases:
324
+ -->
325
+ < p > Vec とは違い、これを直すのは簡単ではありません。一つの選択肢として、ユーザ定義の
326
+ コードとアンセーフなコードを、 2 つの段階に分割することです。</ p >
244
327
< pre > < code class ="language-text "> bubble_up(heap, index):
245
328
let end_index = index;
246
329
while end_index != 0 && heap[end_index] < heap[parent(end_index)]:
@@ -252,14 +335,29 @@ <h2><a class="header" href="#binaryheapsift_up" id="binaryheapsift_up">BinaryHea
252
335
index = parent(index)
253
336
heap[index] = elem
254
337
</ code > </ pre >
255
- < p > If the user-defined code blows up, that's no problem anymore, because we haven't
338
+ <!--
339
+ If the user-defined code blows up, that's no problem anymore, because we haven't
256
340
actually touched the state of the heap yet. Once we do start messing with the
257
341
heap, we're working with only data and functions that we trust, so there's no
258
- concern of panics.</ p >
259
- < p > Perhaps you're not happy with this design. Surely it's cheating! And we have
260
- to do the complex heap traversal < em > twice</ em > ! Alright, let's bite the bullet. Let's
261
- intermix untrusted and unsafe code < em > for reals</ em > .</ p >
262
- < p > If Rust had < code > try</ code > and < code > finally</ code > like in Java, we could do the following:</ p >
342
+ concern of panics.
343
+ -->
344
+ < p > もしユーザ定義のコードでトラブっても、もう問題ありません。なぜなら、
345
+ ヒープの状態にはまだ触れていないからです。ヒープを実際に弄るとき、
346
+ 信用しているデータや関数のみを扱っています。ですからもうパニックの心配は
347
+ ありません。</ p >
348
+ <!--
349
+ Perhaps you're not happy with this design. Surely it's cheating! And we have
350
+ to do the complex heap traversal *twice*! Alright, let's bite the bullet. Let's
351
+ intermix untrusted and unsafe code *for reals*.
352
+ -->
353
+ < p > 多分、この設計を嬉しく思わないでしょう。明らかに騙している! そして複雑な
354
+ ヒープのトラバーサルを < em > 2 回</ em > 行わなければならない! 分かった、我慢しよう。
355
+ 信用していないコードやアンセーフなコードを< em > 本気で</ em > 混ぜてみよう。</ p >
356
+ <!--
357
+ If Rust had `try` and `finally` like in Java, we could do the following:
358
+ -->
359
+ < p > もし Rust に Java のような < code > try</ code > と < code > finally</ code > があったら、コードは
360
+ こんな感じだったでしょう。</ p >
263
361
< pre > < code class ="language-text "> bubble_up(heap, index):
264
362
let elem = heap[index]
265
363
try:
@@ -269,18 +367,31 @@ <h2><a class="header" href="#binaryheapsift_up" id="binaryheapsift_up">BinaryHea
269
367
finally:
270
368
heap[index] = elem
271
369
</ code > </ pre >
272
- < p > The basic idea is simple: if the comparison panics, we just toss the loose
370
+ <!--
371
+ The basic idea is simple: if the comparison panics, we just toss the loose
273
372
element in the logically uninitialized index and bail out. Anyone who observes
274
- the heap will see a potentially < em > inconsistent</ em > heap, but at least it won't
373
+ the heap will see a potentially * inconsistent* heap, but at least it won't
275
374
cause any double-drops! If the algorithm terminates normally, then this
276
- operation happens to coincide precisely with the how we finish up regardless.</ p >
277
- < p > Sadly, Rust has no such construct, so we're going to need to roll our own! The
375
+ operation happens to coincide precisely with the how we finish up regardless.
376
+ -->
377
+ < p > 基本的な考えは単純です。すなわち、もし比較においてパニックしたのなら、単に要素を
378
+ 論理的に未初期化のインデックスの位置に保存し、脱出します。このヒープを観察する誰もが、
379
+ 潜在的には< em > 一貫性のない</ em > ヒープを目にするでしょうが、少なくともこのコードは二重ドロップを
380
+ 起こしません! もしアルゴリズムが通常通り終了すれば、この操作はコードがどのように終了するかに
381
+ 関わらず、結果を正確に一致させるために実行されます。</ p >
382
+ <!--
383
+ Sadly, Rust has no such construct, so we're going to need to roll our own! The
278
384
way to do this is to store the algorithm's state in a separate struct with a
279
- destructor for the "finally" logic. Whether we panic or not, that destructor
280
- will run and clean up after us.</ p >
385
+ destructor for the "finally" logic. Whether we panic or not, that destructor
386
+ will run and clean up after us.
387
+ -->
388
+ < p > 悲しいことに、 Rust にはそのような構造が存在しません。ですので、自分たちで退避させなければ
389
+ ならないようです! これを行なうには、 "finally" の論理を構成するため、デストラクタと共に
390
+ アルゴリズムの状態を、別の構造体に保存します。パニックしようがしまいが、デストラクタは
391
+ 実行され、状態を綺麗にします。</ p >
281
392
< pre > < code class ="language-rust ignore "> struct Hole<'a, T: 'a> {
282
393
data: &'a mut [T],
283
- /// `elt` is always `Some` from new until drop.
394
+ /// `elt` は new で生成されたときからドロップまで、常に Some です
284
395
elt: Option<T>,
285
396
pos: usize,
286
397
}
@@ -313,7 +424,7 @@ <h2><a class="header" href="#binaryheapsift_up" id="binaryheapsift_up">BinaryHea
313
424
314
425
impl<'a, T> Drop for Hole<'a, T> {
315
426
fn drop(&mut self) {
316
- // fill the hole again
427
+ // 穴を再び埋めます
317
428
unsafe {
318
429
let pos = self.pos;
319
430
ptr::write(&mut self.data[pos], self.elt.take().unwrap());
@@ -324,15 +435,15 @@ <h2><a class="header" href="#binaryheapsift_up" id="binaryheapsift_up">BinaryHea
324
435
impl<T: Ord> BinaryHeap<T> {
325
436
fn sift_up(&mut self, pos: usize) {
326
437
unsafe {
327
- // Take out the value at `pos` and create a hole.
438
+ // `pos` にある値を受け取り、穴を作ります。
328
439
let mut hole = Hole::new(&mut self.data, pos);
329
440
330
441
while hole.pos() != 0 {
331
442
let parent = parent(hole.pos());
332
443
if hole.removed() <= hole.get(parent) { break }
333
444
hole.move_to(parent);
334
445
}
335
- // Hole will be unconditionally filled here; panic or not !
446
+ // 状況に関わらず、穴はここで埋まります。パニックしてもしなくても !
336
447
}
337
448
}
338
449
}
0 commit comments