2015-06-18 2 views

ответ

12

Давайте посмотрим на то, как std::mem::drop реализуется:

pub fn drop<T>(_x: T) { } 

Правильно: это пустая функция! Это потому, что он использует преимущества семантики перемещения, чтобы получить право собственности на свой аргумент. Если T реализует Drop, компилятор автоматически вставляет вызов в Drop::drop(_x) в конце функции. Это происходит со всеми аргументами, полученными по значению (то есть, фактически, все аргументы, но сброс ссылки не отбрасывает референт).

Теперь рассмотрим, что произойдет, если Drop::drop взял свой аргумент по значению: компилятор попытается вызвать Drop::drop на аргумент в Drop::drop — это может вызвать переполнение стека! И, конечно, вы могли бы вызвать mem::drop по аргументу, который также попытался бы рекурсивно вызвать Drop::drop.

6

На самом деле, для Drop::drop нет необходимости владеть стоимостью.

В Rust владение автоматически обрабатывается на уровне языка, и поэтому компиляция гарантирует правильную реализацию семантики владения; таким образом, когда Foo { a: int, b: String } выходит за пределы области видимости, компилятор отбрасывает Foo, автоматически отбрасывая свои внутренние поля.

Таким образом, нет необходимости в Drop::drop, чтобы сбросить все поля!

На самом деле, после того, как Drop::drop вызывается Foo, компилятор будет сам mem::drop различные поля (которые также могут взывают Drop::drop на тех областях, которые определяют его, например, b: String здесь).


Что делает Drop::drop do, then?

Используется для реализации дополнительных логики поверх того, что сделает компилятор; принимая ваш JoinHandle пример:

#[stable(feature = "rust1", since = "1.0.0")] 
#[unsafe_destructor] 
impl<T> Drop for JoinHandle<T> { 
    fn drop(&mut self) { 
     if !self.0.joined { 
      unsafe { imp::detach(self.0.native) } 
     } 
    } 
} 

Здесь Drop::drop используется для отсоединения нити, например.

В коллекции, такие как Vec::vec:

#[unsafe_destructor] 
#[stable(feature = "rust1", since = "1.0.0")] 
impl<T> Drop for Vec<T> { 
    fn drop(&mut self) { 
     // This is (and should always remain) a no-op if the fields are 
     // zeroed (when moving out, because of #[unsafe_no_drop_flag]). 
     if self.cap != 0 && self.cap != mem::POST_DROP_USIZE { 
      unsafe { 
       for x in &*self { 
        ptr::read(x); 
       } 
       dealloc(*self.ptr, self.cap) 
      } 
     } 
    } 
} 

Здесь, в качестве исходных памятей манипулируют таким образом, непрозрачную, чтобы компилятор, эта реализация берет на себя:

  1. Отбрасывания каждого элемента проведен по вектору
  2. Освобождение памяти
+1

Извините, я wasn ' t ясно. Я не собираюсь вручную удалять каждое поле. Мое намерение состоит в вызове функций, которые потребляют некоторые из моих полей, чтобы я мог ждать по потоку или регистрировать любые ошибки (я признаю, что я не должен был поднимать 'std :: mem :: drop', который не говорит вам любые ошибки, которые произошли). – yonran

+1

@yonran: Ну, прося логическое обоснование, как вы это делали, является правильным вопросом, поэтому я неохотно говорю вам, что вы его редактируете и полностью меняете, вместо этого я бы посоветовал вам просто задать другой вопрос о том, как делать то, что вы хотите сделайте, желательно с MCVE на [playpen] (https://play.rust-lang.org/), с которым мы можем возиться, чтобы убедиться, что наше решение компилируется. –

+0

@yonran: Вы когда-нибудь задавали другой вопрос? У меня такая же проблема, как у вас; в частности с использованием '' WavWriter :: finalize() '] (https://docs.rs/hound/3.0.0/hound/struct.WavWriter.html#method.finalize) в' Drop() '. – Timmmm