Smart pointers give you reference counting at best. Language implementations tend to have a lot of reference cycles, so you need actual GC (or a very sophisticated kind of manual memory management)