You are correct. The list would clean itself up. As the author stated:
All that's handled for us automatically... with one hitch.
They then explain why the automatic handling is bad:
The automatic destruction process calls drop
for the head of the list, which in turn calls drop
for the first element. And so on and so on.
This is a function calling a function calling a function (with infinite possible repetitions) which will blow up your stack sooner or later.
This test causes such a stack overflow:
#[test]
fn build_really_big_stack() {
let mut stack = List::new();
for i in 0..1_000_000 {
stack.push(i);
}
}
If you build with --release
for both versions, it shows that they perform nearly equally:
#[bench]
fn bench_auto_destructor(b: &mut Bencher) {
b.iter(|| {
let mut list = List::new();
for i in 0..1000 {
list.push(i);
}
assert_eq!(list.pop(), Some(999));
});
}
#[bench]
fn bench_man_destructor(b: &mut Bencher) {
b.iter(|| {
let mut list = ManualDestructorList::new();
for i in 0..1000 {
list.push(i);
}
assert_eq!(list.pop(), Some(999));
});
}
test bench_auto_destructor ... bench: 81,296 ns/iter (+/- 302)
test bench_man_destructor ... bench: 85,756 ns/iter (+/- 164)
With only one element, like in your benchmarks:
test bench_auto_destructor ... bench: 69 ns/iter (+/- 1)
test bench_man_destructor ... bench: 67 ns/iter (+/- 2)
Read the article to the end, its explanation is better than mine.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…