But this control comes at a price: You need to be very careful. You need to manage memory manually, you need to avoid accidentally writing into memory you don't own, and so on. Overlooking small details results in security bugs.
Rust attempts to provide the same low-level control as C and C++, but it adds safeguards which keep you from shooting yourself in the foot. In "safe" mode, all of these safeguards are fully engaged. In "unsafe" mode, Rust allows you to do some sketchy things. The idea is to use as much safe code as you can, and only use a tiny amount of unsafe code if you need to do something Rust can't prove to be safe.
For example, there's a great series of blog posts about writing a toy OS kernel in Rust: http://blog.phil-opp.com/ The author uses some assembly to set things up, and a tiny amount of "unsafe" Rust to directly access VGA memory. But all the higher level code is safe, which rules out a whole class of bugs.
Personally, I've spent a lot time using both C++ and functional languages. And for me, Rust hits a sweet spot: I can get down to the metal when I want, and I can build nice abstractions. And I can write almost all my code in "safe" mode, and not worry about dumb pointer bugs. It's an interesting combination and it makes me want to hack on new things. :-)
So, I am not sure what you mean?
You should always be using make_unique and make_shared for heap allocations and you use shared whenever an object is being passed around and needs to track its owners, unique is for single-usage-instance use cases.
Those smart pointers have minimal overhead, deterministic runtime, and have no more overhead than manual implementations of the same mechanisms with raw pointers.
That is also how Rust does it - references are smart pointers, so you avoid having a GC.
Rust's &T (references) are entirely checked at compile time, and generate the exact same code as a regular old C pointer would. No wrappers, extra allocations, reference counts, move/copy/whatever constructors (not that Rust even has those, but are important for C++ smart pointers).
It's not a perfect analogy, but perhaps gets a bit of the flavour difference.
Basically, safe code is automatically managed to get rid of memory leaks [0], dangling pointers [1], null pointer dereferencing [2], race conditions [3], and many other memory management bugs.
You don't encounter any of these in JavaScript because it's a managed language, meaning there's a garbage collector [4] that looks after all your memory allocations.
Contrary to the managed languages, C & C++ are unsafe and "native" (meaning that they're very close to the hardware level) - it's a wild land where you manage memory manually yourself. If you miss a single deallocation, you're left with a memory leak. If you deallocate a memory region twice, you have a double free situation [5]. So you have to be very cautious when writing code in C & C++. There are many techniques to make it easier (e.g. smart pointers [6]), but not all developers use them.
Rust takes the middle ground: it combines safety with unsafety by using a know-how affine type system with a borrow checker, which allows values/variables to have only one owner. This system has properties of both managed and unmanaged code. "Unsafe" code in the context of Rust means that you consciously turn off the borrow checker, leaving on your own and managing memory deallocations manually, as in C. That makes it possible to interface your Rust code with the native code, at the cost of making you prone to all errors and bugs that are listed above. So it's a good thing to minimize usage of unsafe code, to allow the Rust compiler to check your code for safety.
[0] https://en.wikipedia.org/wiki/Memory_leak
[1] https://en.wikipedia.org/wiki/Dangling_pointer
[2] https://en.wikipedia.org/wiki/Null_pointer#Dereferencing
[3] https://en.wikipedia.org/wiki/Race_condition
[4] https://en.wikipedia.org/wiki/Garbage_collection_(computer_s...
[5] http://stackoverflow.com/questions/21057393/what-does-double...
Not everyone has security as a requirement. Some people jsut want to write something that is both fast, predicable. Most banks don't make any security demands of internal applications because they are not accessible to the internet. At which point safety is just a way to slow you do.
This is a bad way of doing things. That means as soon as someone finds a way to get inside the network, the bank is wrecked. You need to look at security from the point of assuming the attacker somehow got inside because it'll happen one day.
http://digg.com/2015/ashley-madison-hack
""" MOTHERBOARD: How did you hack Avid Life Media? Was it hard?
The Impact Team: We worked hard to make fully undetectable attack, then got in and found nothing to bypass.
MOTHERBOARD: What was their security like?
The Impact Team: Bad. Nobody was watching. No security. Only thing was segmented network. You could use Pass1234 from the internet to VPN to root on all servers. """
And debuggable? Not crashing in random places due to stack or heap corruption helps there.
This most definitely is not the view taken at the financial companies I've worked in/with including a number of banks.
They take internal security very seriously. There's the obvious threat of some form of break-in (no-one I know seriously believes that an unbreachable connected system is buildable). But there's also the issues of insiders taking stuff, Chinese walls and regulatory restrictions on access. It simply doesn't make economic sense to take security lightly any more.
"Because that's where all the exploitable attack vectors in unsafe code are."
Whilst obviously Internet facing apps are treated with more caution, it's definitely not true in my experience to state that there are no security demands on internal applications. I would expect that most/all banks these days realise that there's no such thing as a fully trusted network...
> How does it relate to writing C++11 without using raw pointers.
Rust's safety features are similar to those, but even stronger in a number of ways. There's two aspects to this: 1. more guarantees. You can write code with uniq_ptr that segfaults, but you cannot with Box<T>. 2. safety allows for patterns that would be dangerous in C++. For example, shared_ptr uses atomics for thread safety. Rust has two variants, Arc<T> with similar atomics, and Rc<T> without. If you're not using multiple threads, you can use Rc<T>, safe in knowing that Rust will give you a compile-time error if you introduce multithreading. In other words, there are ways that you need to be defensive in C++ that you do not in Rust. > does it have the capabilities C++ has regarding making classes,
Rust does not really have OOP, exactly, we have structs and traits (concepts). One major difference is that we don't currently have inheritance, though proposals are being worked on. But since we already have the concept equivalent, we have extra power there. Tradeoffs. > operator overloading
Rust lets you overload certain pre-defined operators, but not create new ones. > templates?
AST based, hygenic macros, instead.Well and generics & traits. 99% of the places where C++ programmers use templates, they would use generics in Rust. `template std::vector<T>` <-> `Vec<T>` etc.
It's only the niche metaprogramming ability of C++'s templates that would be replaced with macros.
auto v = std::vector<int> {1, 2, 3}
for (auto x : v) {
if (x > 0) {
v.push_back(-x);
}
}
The above may segfault, do what you expect it to, run forever etc. Unchecked indexing, branching on uninitialized data etc.Rust frees you from _all_ of these things and offers a bunch of further advantages, most notably: data race freedom. You can actually share data between threads and keep your sanity.
A few of the improvements that Rust offers are compiler enforced move semantics by default, so assigning, returning, or passing a Box<T> (similar to unique_ptr<T> in C++) will move the ownership to the new location and statically check that you never try to access the old location. In C++, you have to explicitly call std::move(), and checks to make sure you don't reference the old one happen at runtime.
Rust also does safer checking of use of references. In C++, it's possible to return a reference to a stack variable which is no longer valid. In Rust, the lifetimes of references are tracked statically, so you can never have a dangling reference.
So, while the RAII pattern, use of smart pointers, and use of references, will feel fairly familiar to someone familiar with modern C++, they are actually generally more convenient and more safe in Rust.
Rust does not have classes. You define plain old data structures, and use traits to provide polymorphic behavior. Traits are somewhat like interfaces which can contain default implementations of methods. Traits can be used to constrain types. Traits can be used to provide either static (compile time) dispatch, or runtime dispatch, depending on whether the object is monomorphized at compile time or accessed through a fat pointer that includes a vtable to dispatch at runtime.
Rust provides generics which fill a similar niche to templates in C++. In some ways, they are more powerful as arguments can be constrained by traits; in some ways they are less powerful than C++ templates.
For an introduction to traits in Rust, take a look at the book: https://doc.rust-lang.org/book/traits.html
Rust doesn't provide operator overloading directly, but use of operators is equivalent to just calling a method defined on a particular trait in Rust. So, "a + b" is will work for any types that implement the Add trait (https://doc.rust-lang.org/std/ops/trait.Add.html), and is equivalent to calling a.add(b).
The vast majority of C++ template usage is acheived by generics, and in a much more type safe and debugable manner.
Most of the remaining things can be achieved by Rust's hygenic macros (which are not like C++ macros, they're more like C++ templates in how they can be used and the guarantees they provide).