C+
Ownership & safety · v0.0.13

Drop & defer

Drop: your destructor

A struct that defines a method literally named drop runs that method on scope exit. The signature is fixed: fn drop(mut self), with no return type.

struct Buf { ptr: *u8, len: usize }
impl Buf {
    fn drop(mut self) {
        unsafe { free(self.ptr); }
    }
}

fn main() -> i32 {
    let b: Buf = make_buf();
    // ... use b ...
    return 0;
}                                    // b.drop() runs here

Defining drop makes the type non-Copy, which is necessary: copying a value that owns a resource would lead to a double free. See Ownership for how Copy is derived.

Raw-pointer accountability

A drop frees its struct's fields by hand; the compiler does not synthesize per-field drops. For a raw-pointer field (*T) the compiler cannot tell whether the struct owns the memory or only borrows it, so it makes you say which. A raw-pointer field that is neither released by the struct's drop nor marked opaque is a compile error (E0510). There is no silent-leak default.

struct Buf { ptr: *u8, len: usize }
impl Buf {
    fn drop(mut self) { unsafe { free(self.ptr); } }   // owned: you free what you own
}

struct View { opaque ptr: *u8, len: usize }            // borrowed: `opaque` means "not mine"

Severity tracks what the compiler can prove about the drop body. It is a structural check, with no dataflow:

The field's release in drop is... Result
unconditional, or guarded only by a null-test on the same field clean
present but conditional (a refcount, flag, or loop, so it cannot be proven to always run) W0002 warning
absent, delegated to a helper, or there is no drop at all E0510 error
the field is marked opaque clean (managed elsewhere)

free(self.ptr as *u8) counts as releasing ptr, since the cast is transparent. The warning case is for legitimately conditional owners such as refcounted types, which free their control block only on the last reference. Use opaque only when another owner truly frees the pointer: an FFI handle the runtime owns, a borrowed view, or a pointer freed by a sibling struct.

defer: run at scope exit, LIFO

defer schedules an action to run when the scope exits, in last-in-first-out order:

fn main() -> i32 {
    println(1);
    defer println(4);
    defer println(3);
    println(2);
    return 0;
}
// Prints 1, 2, 3, 4

defer and Drop share one scope-exit stack: they interleave in declaration order and are popped LIFO at exit.