This week I had a nice discussion on Smart Pointer versus RUST. My takeaways are the following.
| Feature | C++ Smart Pointers | Rust Ownership & Borrowing (also has SmartPointer) |
|---|
| Goal | Manage dynamic memory with RAII – “Resource Acquisition Is Initialization” | Ensure memory safety at compile time |
| Core Concept | Pointer with automatic resource release | Ownership rules enforced by the compiler |
| Memory Safety | Runtime safety via smart pointers | Compile-time safety via borrow checker |
And while programming
| Concept | C++ | Rust |
|---|---|---|
| Unique ownership | std::unique_ptr<T> | Box<T> (heap allocation) + ownership transfer |
| Shared ownership | std::shared_ptr<T> | Rc<T> (single-threaded), Arc<T> (thread-safe) |
| Non-owning reference | Raw pointer or std::weak_ptr<T> | &T (immutable borrow), &mut T (mutable borrow) |
| Null safety | nullptr possible | No null references (Option<T> is used instead) |
Code example:
#include <memory>
std::unique_ptr<int> makeInt() {
return std::make_unique<int>(42);
}
int main() {
std::unique_ptr<int> ptr = makeInt();
// *ptr = 10; // OK
}
fn make_int() -> Box<i32> {
Box::new(42)
}
fn main() {
let ptr = make_int();
// *ptr = 10; // OK
}
Same ease of use
Safety considerations
| Category | C++ | Rust |
|---|
| Dangling pointers | Possible if raw pointers or misused shared_ptr | Prevented by ownership rules |
| Use-after-free | Possible, unless smart pointers are carefully used | Statistically eliminated by borrow checker |
| Data races | Possible in multithreaded contexts | Compiler prevents them via aliasing rules |
| Reference counting | Runtime cost with shared_ptr/weak_ptr | Runtime cost with Rc/Arc, compile-time borrow checks otherwise |
| Zero-cost abstraction | Not guaranteed | Strong focus on zero-cost abstractions |
Reference Cycles
But also consider this nice chapter in the RUST handbook: Reference Cycles Can Leak Memory – The Rust Programming Language
Even though Rust enforces strict memory safety at compile time, reference cycles are still possible when using reference-counted types like Rc<T> or Arc<T>—similar to shared_ptr in C++. This is one of the few scenarios in which Rust can leak memory, albeit safely (i.e., without undefined behavior).
| Concept | C++ | Rust |
|---|---|---|
| Reference cycles | Can occur with std::shared_ptr | Can occur with Rc<T> or Arc<T> |
| Prevention | Use std::weak_ptr to break cycles | Use Weak<T> to break cycles |
| Memory leak risk | Yes, if cycles are not broken | Yes, in same cases — logic errors, not unsafe |
| Runtime check? | No automatic detection | No automatic detection eitherEven though Rust enforces strict memory safety at compile time, reference cycles are still possible when using reference-counted types like Rc<T> or Arc<T>—similar to shared_ptr in C++. This is one of the few scenarios in which Rust can leak memory, albeit safely (i.e., without undefined behavior).Concept C++ Rust Reference cycles Can occur with std::shared_ptrCan occur with Rc<T> or Arc<T>Prevention Use std::weak_ptr to break cyclesUse Weak<T> to break cyclesMemory leak risk Yes, if cycles are not broken Yes, in same cases — logic errors, not unsafe Runtime check? No automatic detection No automatic detection either |