From C++ to Rust: Error Handling and Lifetimes
The article, the second in the “From C++ to Rust” series, explains how Rust replaces C++’s return‑value and exception error handling with the Result type, the ? operator, and the thiserror/anyhow crates, and introduces Rust’s lifetime system, borrow checker, elision rules, variance, and common misconceptions for developers transitioning from C++.
This article is the second part of the "From C++ To Rust" series, focusing on error handling and lifetimes - two critical topics for developers transitioning from C++ to Rust.
Error Handling:
C++ typically uses two error handling approaches: return value style (inherited from C) and exceptions. The return value style is explicit but mixes error handling code with business logic, while exceptions keep business logic clean but introduce exception safety issues and implicit control flow.
Rust uses Result<T, E> for recoverable errors and panic! for unrecoverable ones. The Result enum is defined as:
pub enum Result<T, E> {
Ok(T),
Err(E),
}The ? operator provides syntactic sugar for error propagation, equivalent to pattern matching that returns errors. Rust achieves a balance by not having exceptions (keeping simple return-value-based control flow analysis) while ensuring errors cannot be silently ignored through the type system.
For error handling conventions, the article discusses thiserror for library-level errors and anyhow for application-level errors, with examples showing how to use map_err and the From trait for error type conversion.
Lifetimes:
Lifetimes are Rust's unique approach to memory safety without garbage collection. The BorrowChecker performs static analysis at compile time to ensure references are valid.
The article explains lifetime elision rules: each input reference gets its own lifetime; if there's only one input reference, its lifetime is assigned to all output references; if there are multiple input references with &self or &mut self, self's lifetime is assigned to output references.
Key concepts covered include subtyping and variance: 'static is a subtype of all other lifetimes (longer lifetime = more useful = subtype). The article explains covariance, contravariance, and invariance with examples like &'a mut T being invariant to prevent type safety issues.
Common misconceptions addressed include: T is a supertype of both &T and &mut T; &T and &mut T are disjoint sets; T: 'static means the type is bounded by the 'static lifetime and can include owned types, not just references.
Tencent Cloud Developer
Official Tencent Cloud community account that brings together developers, shares practical tech insights, and fosters an influential tech exchange community.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.