Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Drop と #[may_dangle]

Drop を手動で実装するジェネリックな Type<T> は、T#[may_dangle] 属性が適切かどうかを検討すべきです。Nomicon には、#[may_dangle] が何であるかについての詳細があります。

ジェネリックな Type<T> に、T の drop も伴う可能性がある手動の drop 実装がある場合、dropck はそれを知る必要があります。Type<T> による T の所有権が、ManuallyDrop<T>*mut TMaybeUninit<T> のようにそれ自体では T を drop しない型を通じて表現されている場合、Type<T> には T が drop される可能性があることを dropck に伝えるための PhantomData<T> フィールドも必要です。標準ライブラリ内で内部の Unique<T> ポインター型を使用している型には、PhantomData<T> マーカーフィールドは必要ありません。それは Unique<T> によって処理されます。

これが実際にどのように問題になり得るかの例として、次のような OptionCell<T> を考えてみましょう。

struct OptionCell<T> {
    is_init: bool,
    value: MaybeUninit<T>,
}

impl<T> Drop for OptionCell<T> {
    fn drop(&mut self) {
        if self.is_init {
            // Safety: `is_init` が true の場合、`value` は完全に初期化されていることが保証されます。
            // Safety: セルは drop されている最中なので、再びアクセスされることはありません。
            unsafe { self.value.assume_init_drop() };
        }
    }
}

PhantomData<T> マーカーフィールドを持たないこの OptionCell<T>#[may_dangle] 属性を追加すると、OptionCell<T> より厳密には長く生存しない T に対して健全性の穴が生じ、それらが自身の Drop 実装内で、drop された後にアクセスされる可能性がありました。#[may_dangle] を正しく適用するには、PhantomData<T> フィールドも必要でした。

struct OptionCell<T> {
    is_init: bool,
    value: MaybeUninit<T>,
+   _marker: PhantomData<T>,
}

- impl<T> Drop for OptionCell<T> {
+ unsafe impl<#[may_dangle] T> Drop for OptionCell<T> {

レビュアー向け

手動の Drop 実装がある場合は、#[may_dangle] が適切かどうかを検討してください。適切である場合は、Unique<T> を通じて、または直接フィールドとして、PhantomData<T> も存在することを確認してください。