Destructors that can fail¶
Level: 301 · deep dive
One line: Drop::drop takes &mut self, returns nothing and cannot be async on stable — so a close that can fail, such as a final flush or a commit, needs an explicit close(self) -> Result<…> beside a Drop that only cleans up whatever was left.
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The bullets below are the questions the finished page has to answer.
What it has to cover¶
- The signature and its limits:
fn drop(&mut self)has no return value and noasync;core::future::AsyncDropexists on 1.98.0 only as a nightly-only experimental API (async_drop, issue #126482) - std admitting it in its own docs:
BufWritersays errors during the flush on drop are ignored and asks you to callflushfirst;Filesays errors detected on closing are ignored by itsDropand points tosync_allfor anyone who needs them - The explicit close taking
selfby value, so nothing can use the value afterwards — std's version isBufWriter::into_inner, which flushes and returnsResult<W, IntoInnerError<BufWriter<W>>> - The
Dropthat stays behind: a field (Option<Inner>, or aclosedflag) thatcloseclears, sodropcan tell a closed value from an abandoned one — and what it should do with an abandoned one: flush and ignore, log, ordebug_assert!? - Panicking instead of ignoring: why a panic inside
dropwhile the thread is already unwinding aborts the process, and the Guidelines' C-DTOR-FAIL, "Destructors never fail" - Blocking in
drop(C-DTOR-BLOCK): joining a thread or waiting on a socket in a destructor, why that is worse inside an async runtime, and the explicit alternative the guideline asks for Dropis not guaranteed to run —mem::forgetandRccycles skip it (Drop, and what RAII buys) — so anything that must happen has to go throughclose, andDropcan only be the fallback- Rust for Rustaceans ch. 3 → "Flexible" → "Fallible and Blocking Destructors" as the source
The trap it exists for¶
Letting a BufWriter flush on drop at the end of main. If that last write fails — a full disk, a closed pipe — the error is discarded with the writer, the program exits 0, and the report on disk is short. One writer.flush()? before the end turns the silent truncation into an error message.
Where this sits¶
Drop, and what RAII buys covers drop order and what Drop cannot do; Drop guards covers the guard pattern built on it; Read and Write holds the same BufWriter trap from the I/O side. This page is the API a library offers when closing its resource can fail.
See also¶
Drop, and what RAII buys — whatDropcannot do, including fail- Drop guards — cleanup on every exit path, and what a guard cannot report
ReadandWrite— flushing, and the error aBufWriterthrows away- Readers are fallible — I/O errors that arrive after the open succeeded
- Making misuse a compile error —
#[must_use]and types that force the explicit close BufWriter↗ — the paragraph on flushing before drop, andinto_inner- Rust API Guidelines — Dependability ↗ — C-DTOR-FAIL and C-DTOR-BLOCK
If you are coming from another language¶
- C++. Destructors are implicitly
noexceptsince C++11, so a throw escaping one callsstd::terminate— the same "do not fail here" rule, enforced at run time.std::ofstreamalso closes quietly in its destructor; callingclose()and checking the stream state is the explicit path, asclose(self) -> Resultis in Rust. - Java.
AutoCloseable.close()is declaredthrows Exception, and try-with-resources calls it and reports the failure — attaching it as a suppressed exception when the body had already thrown. Java made the close explicit syntax rather than a destructor. - Go.
defer f.Close()discards the errorClosereturns. The usual fix is a named result that the deferred function overwrites if closing failed — an explicit close, written by hand every time. - Python. An exception from
__exit__propagates out of thewithblock; one raised in__del__is printed as "Exception ignored" and dropped — Python has both halves of this page, a reporting close and a swallowing destructor.
Po polsku¶
Drop::drop nie zwraca Result i nie może być async, więc zamknięcie, które może się nie udać — ostatni zapis bufora, zatwierdzenie transakcji — musi mieć jawną metodę close(self) -> Result<…>, a Drop zostaje tylko do sprzątania tego, czego nikt nie zamknął. Sama biblioteka standardowa to przyznaje: BufWriter i File ignorują błędy przy zwalnianiu. Pułapka: program kończy się kodem 0, a plik na dysku jest ucięty, bo błąd ostatniego zapisu zniknął razem z BufWriter.
Szukaj po polsku: destruktor zwracający błąd · jawne zamykanie zasobu · rust drop cannot return error · rust bufwriter flush on drop · rust async drop