A destructor performs cleanup when an object is destroyed. This matters when a function can return early: a cleanup call written at the end of the function may never run. Resource acquisition is initialization (RAII) ties cleanup to an object's lifetime instead of relying on every return path to reach that call. section 4.1.1
void leaky_func() {
FILE *fp;
int *a = malloc(sizeof(int));
*a = 0; #1
// try to open a file for reading
fp = fopen("file.txt", "r");
if (fp == NULL) {
// there was an error!
return;
}
// Now we can read from the file at fp.
// ...
fclose(fp); #2
free(a); #3
}
The failed file-open path returns before `free(a)`, leaking the allocated memory. section 4.1.1
In C++, a stack object's destructor runs when it leaves scope. A smart pointer can use that guarantee to pair allocation with release, even on an early return. The protection depends on using the smart pointer rather than managing the allocation manually. section 4.1.1
Rust also destroys an owned value when it goes out of scope. Ownership moves determine *which* variable owns the value at that point: moving a `String` into a `Vec` leaves the vector responsible for it. A container's destruction also destroys its contents. The special `Drop` trait provides a destructor through `fn drop(&mut self)`. section 4.1.2 section 2.2.5
Listing 4.1 Resource acquisition
fn main() {
let status = String::from("Active"); #1
let statuses = vec![status]; #2
println!("{:?}", statuses);
} #3
Follow `status` into `statuses`: the move transfers ownership, so cleanup follows the vector's lifetime rather than the original binding. section 4.1.2
Do not rely on a destructor for a `Copy` value. Such values are copied by value rather than moved, and a `Copy` type cannot define a destructor. For owned, non-`Copy` values, use scope and ownership to reason about when cleanup happens; keep unsafe code in mind as an exception to the ordinary RAII account. section 4.1.2


