An In-Depth Comparison of Rust and C++
Benchmarks, tradeoffs, and more
I have written two articles about or relating to the Rust language in the last month. The problem with writing about a specific language is that I haven’t really presented a case for why this language that I love is superior to alternatives, and that is what I intend to do today.
My history in programming began when I was six years old, when my uncle pulled me aside one day and asked me, very seriously, if I wanted to learn to do what he did.
Earnestly, I replied yes and immediately, he began setting me up with lessons on the C language. Soon, C became C++ and then, I became enamored with Python. My stint of interest in Python confounds me to this day.
The syntax of Python feels completely foreign when compared to something like C++ and to this day, I still do not know what possessed me to learn it, but that is something I live with. (Sarcasm…)
After a while, however, Python became Java, Java became JavaScript, and JS became C#. And then, on my journey back to C++, I came across a new language: Rust.
Now that we have a little bit of my background out of the way, let’s start this comparison by looking at ecosystems.
Ecosystem
When you compare programming languages, you have to compare the ecosystems behind them. It’s not enough to just look at raw statistics, you have to go deeper and look at the ecosystem behind the language.
The number of developed and actively maintained libraries gives you a sense of what you can expect from the language and the community of developers that surrounds it.
Comparing Rust and C++, specifically, there’s a clear winner in C++. Rust has a robust set of libraries and frameworks available, but C++ has a lot more to pick from and has more active developers in the community behind it.
To save time, we’ll look at three categories: web, game, and UI development.
Web
Crates like Rocket, Actix, or Nickel allow for the rapid development of web applications on a small and even large scale in the Rust language. Crates like that are the gold standard for the community behind Rust, although there are quite a few other options like Warp and Gotham.
C++ has a few options in this department such as CppCMS and Wt. There are more, but those are the two I could come up off the top of my head.
Game
Game development is a popular topic for many reasons and C++ is one of the most, if not the most, popular languages for game development, mostly because of its low-level, high-performance aspects.
Rust isn’t all that popular in game development, mostly because it’s a newer language with fewer options for frameworks and the like. In recent times, however, interest in Rust for game development has surged because interest in Rust, as a language, has surged.
There are a lot of library options for game development in C++. Each one has its merits, although some are better than others in more than one or two ways. One such option is Godot. Godot is a game engine not unlike Unity or Unreal, albeit a lot less polished. It’s open-source, like a lot of C++ options.
Rust, however, is a bit of a different story. There aren’t all that many game development options for the Rust language, mostly due to the immaturity of the language and its community.
There are two big names for game engines in Rust: Piston and Amethyst. These engines, like Godot, are open-source and have repositories on GitHub.
User interface
UI development is another popular area. C++ isn’t typically the first option for UI development, given the inherent low-level aspects of the language, and the same applies to Rust.
There are, however, quite a few options available for user interfaces for those so inclined to take the extra time for the additional low-level control that these languages provide.
One example of C++ is GTKmm, a modern C++ interface for the popular GTK+ C library. The library is well-maintained and, in GNU fashion, is open-source.
An example in the Rust arena is Azul, an open-source, immediate-mode GUI framework. It’s newer, but it’s updated frequently and has an active community behind it.
There is a clear winner, with regards to ecosystems, in C++. It’s just more extensive overall than that of Rust, although both have active, passionate user bases.
Next, we’re going to get into the technical details of each language and compare the two.
Technical Comparison
When comparing two programming languages, one of the things that people tend to look at most is the technical details behind them, like performance benchmarks and such-like.
In dynamically-typed languages such as C++, it is much easier to miss problems and issues in your code. Rust can be described as a statically-typed language on steroids as its code-validating procedure is much stricter than C++.
Rust has a tighter approach to security and code quality than C++, and that’s one of the biggest arguments in favor of Rust.
For example, to prevent data races, Rust’s ownership system ensures that no two threads can reference the same data without borrowing or taking ownership of it, which makes it unavailable to any other thread.
Memory safety
It is standard for system-level languages not to have automatic memory management since features such as garbage collectors can jeopardize performances.
Therefore, C++ is anything but memory-safe to preserve its speed. Therefore, how can Rust, a system-level language, be memory safe?
As previously mentioned, Rust has a system of ownership that enforces a lot of memory safety guarantees. This ownership system removes the need for manual memory management procedures that you’ll find as a base requirement for C or C++.
Recently, C++ has had some RAII (a programming idiom: Resource Acquisition is Initialization) features implemented to remove some of the need for manual memory management. These features, however, don’t really cover all of the issues with memory safety that C++ has under the hood.
Ease of use
Almost anyone who uses Rust can state that programming in this language is easier due to well-defined semantics and the prevention of unwanted behavior. In C++, developers have more issues when trying to avoid undefined behavior.
Expanding on the above, C++ is a deep ocean when compared to Rust since C++ has so many features and opportunities for implementation that it can become challenging to keep track.
However, Rust was not created to be a simple language for beginners. Just as C++, it is a complicated system-level language that helps you figure out the way machines work under the hood.
Abstraction
In C++ or Rust, it is often preferred to utilize code duplication over virtual method calls because of their hard-hitting performance costs. However, zero-cost abstraction features, provided by each of the languages, sort of nullify this issue, mostly.
Pointers
A pointer is a general concept for a variable that contains an address in memory. This address refers to, or “points at,” some other data.
Most lower-level languages have pointers in some way, shape, or form and they’re often used in conjunction with other features of the individual language.
Smart pointers, on the other hand, are data structures that not only act as a pointer but also have additional metadata and capabilities.
C++ has types like std::shared_ptr
and std::unique_ptr
that act as pointers with special features. In Rust, the different smart pointers defined in the standard library provide functionality beyond that provided by references.
One example is the reference counting smart pointer type. This pointer enables you to have multiple owners of data by keeping track of the number of owners and, when no owners remain, cleaning up the data.
Rust and C++ both make heavy use of smart pointers in the form of objects like String
in Rust or std::string
in C++. They provide the developer with the features they’ve come to expect over the years and they are extremely useful in most endeavors.
Raw numbers
Rust doesn’t have any special feature that makes it fast and different from C and/or C++. It is much safer than C++ because of protection mechanisms it follows which, in principle, are also doable in C++ (using std::unique_ptr
and std::shared_ptr
).
To achieve the same kind of safety Rust has, we have to do so explicitly and set down standards and force patterns that increase the development effort. With Rust, the major part that makes it safer is that coding mistakes don’t create run-time errors — it creates compilation errors.
When Mozilla talks about how much more performance they could get out of Servo’s rendering engine, compared to every other browser on the planet, it’s not because Rust is doing something that is impossible with C++, but because Rust makes it more securely achievable with less explicit programming effort.
What this means is that performance in Rust is something that happens because you have these guarantees that make the developer more at ease with exploring higher performance methods.
Mandelbrot
- C++ — 1.51 seconds
- Rust — 1.7 seconds
Fasta
- C++ — 1.46 seconds
- Rust — 1.51 seconds
Pidigits
- C++ — 1.89 seconds
- Rust — 1.75 seconds
N-Body
- C++ — 7.7 seconds
- Rust — 5.98 seconds
Please keep in mind that these numbers are arbitrary and are also dependent on a host of different variables. For those curious about more detailed benchmark information, a link to the benchmarks is available below.
Conclusion
The question of whether Rust is better than C++ or vice versa is a difficult one to answer without bias.
Given the numbers, Rust is better for some tasks, but there is certainly room for error in the benchmarks and the numbers you see above can change based on different variables such as hardware setup and the like.
Thank you for reading.