Fundamentals 26 min read

Rust vs C++ & Go: Surprising Performance, Memory Safety & Development Speed

This article examines Rust’s performance advantages over C++ and Go through benchmark tests on prime number calculations, binary size, runtime speed, memory and CPU usage, and explains Rust’s ownership, borrowing, lifetimes, and concurrency model that provide memory safety without sacrificing efficiency.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
Rust vs C++ & Go: Surprising Performance, Memory Safety & Development Speed

Introduction

When choosing a programming language, developers must balance performance, resource consumption, and development efficiency. Rust stands out by offering high performance, low memory overhead, and strong safety guarantees, making it an intriguing alternative to C++ and Go.

Performance Comparison

Binary Size

Static binaries produced by Rust, C++, Go, and Python differ significantly. Rust binaries are about 249 KB, C++ 129 KB, Go 1.58 MB, and Python 3.88 MB. The conclusion is: Python > Go > Rust > C++ in binary size.

Runtime Speed

Using a prime‑number search (finding all primes below 10,000,000) as a test, Rust consistently outperformed the other languages. In multiple runs across three machines, Rust’s iteration count per minute was higher than C++, which in turn beat Go and Python. The conclusion: Rust > C++ > Go > Python.

Rust’s efficiency even surpasses C++ in some scenarios.

Memory Consumption

Rough measurements show Rust uses about 30 MB, C++ 2.2 MB, Go 124 MB, and Python 190 MB. The ranking is: Python > Go > Rust > C++.

CPU Usage

CPU usage percentages were roughly 12.5 % for both Rust and C++, 24 % for Go, and 13 % for Python, leading to the conclusion: Go > Python > Rust = C++.

Memory Safety

Rust guarantees memory safety without runtime overhead by using an ownership system, borrowing rules, and a strict compile‑time borrow checker. These mechanisms prevent common bugs such as null‑pointer dereferences, use‑after‑free, data races, and dangling references.

Ownership Rules

let obj = String::from("hello");

The variable obj owns the String. Ownership can be transferred, and when the owner goes out of scope the value is automatically dropped.

fn main() {
    let s = String::from("hello");
    let s1 = s; // ownership moves to s1
    // println!("{}", s); // error: s is no longer valid
}

Borrowing Rules

References allow temporary access without taking ownership. Immutable references are the default; mutable references require exclusive access.

fn test(s1: &String) {
    println!("{}", s1);
}

fn main() {
    let s = String::from("hello");
    test(&s); // borrow immutably
    println!("{}", s); // s is still valid
}

Attempting to modify an immutable borrow results in a compile‑time error. Using &mut creates a mutable borrow, which must be unique within its scope.

Lifetime Rules

Every reference has a lifetime that must not exceed the lifetime of the value it points to. The compiler enforces that references never outlive their owners, preventing dangling pointers.

{
    let r; // 'a
    {
        let x = 5; // 'b
        r = &x; // error: 'b does not live long enough
    }
    println!("r: {}", r);
}

Concurrency Safety

Rust’s type system ensures data races cannot occur. Threads must own the data they use, or share it via thread‑safe primitives such as Arc and Mutex.

use std::thread;
fn main() {
    let v = vec![1, 2, 3];
    let handle = thread::spawn(move || {
        println!("Here’s a vector: {:?}", v);
    });
    handle.join().unwrap();
}

When a closure captures a variable, the compiler requires the move keyword or a thread‑safe reference. For shared mutable state, Arc<Mutex<T>> is used.

use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    for h in handles { h.join().unwrap(); }
    println!("Result: {}", *counter.lock().unwrap());
}

Development Efficiency

While Rust’s steep learning curve and strict compiler can slow initial development, the guarantees it provides reduce debugging time dramatically. Once code compiles, memory‑related bugs are largely eliminated.

Cross‑Platform Support

Rust can produce static binaries for Windows, Linux, macOS, ARM, and many other targets, simplifying deployment across diverse environments. It also supports embedded development.

Ecosystem

Rust’s ecosystem is younger than that of Python or Go, but it is growing rapidly, with many popular crates available and increasing community adoption.

Conclusion

Rust delivers high performance comparable to C++, superior memory safety without garbage collection, robust concurrency guarantees, and excellent cross‑platform capabilities. For developers seeking a language that combines efficiency with safety, Rust is a compelling choice.

Benchmark Images

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

concurrencyRustMemory Safety
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.