Rust and RAII Memory Management - Computerphile

218,796
0
Published 2023-02-23

All Comments (21)
  • @cowslaw
    Rust’s borrow checker is one of the most powerful and strict features of any language I’ve ever used, and it’s absolutely wonderful!
  • @refactorear
    9:19 I would say exactly the opposite, in this situation the best for your program is to crash, the worst is to get garbage and continue as if nothing had happened as it might takes months, years or decades to find out such a problem (especially when dealing with processing data and not knowing the kind of output you should expect). What usually happens, though, is that you get intermittent crashes depending on the memory values you get from that dangling pointer. Pretty sure the constructor and destructor in the C++ version needs to have the same name as the class, but that's besides the point of the video.
  • @cno9984
    I like how neither his C++ or Rust code snippets would compile.
  • @anafabula
    That "bob" variable you tried to use three times doesn't exist. And why not show the compiler output? It's very friendly
  • @barbiefan3874
    09:20 - it's pretty much the other way around. Best case - your program crashes, worst - you get wrong data and use it.
  • @Qazqi
    It seems a little apples-to-oranges to have a raw pointer in C++, but have a vector in Rust. Both of the languages have a suitable vector type that uses low-level operations under the hood and packages that up into a nice-to-use type with the hard work done for you. Using the video's examples for the two languages makes it easy for people who aren't familiar with them to walk away with a very incorrect view of C++ that remains pervasive in the field, but doesn't reflect how ordinary code is written at all. The Rust comparison should come in at the point where it starts to offer more guarantees and functionality than what C++ can offer, and point out that it's part of the language rather than static analysis. Even moving (which C++ has too, just different) isn't so much about one owner for something like a vector (the vector already represents a single owner of its memory) as it is about not needlessly copying the vector. Either way works, but one makes copies explicit. There are other contexts where it's more about a single owner for a resource. Borrow checking and trying to use something after it's been moved from are where Rust really starts to bring more to the table in this regard than static analysis with accompanying rules on how to write code so the analyzer can reasonably work with it.
  • 5:50 in C++ you need to tell the compiler if what you're deleting is an array with delete[] instead of delete. In that example the memory won't have been freed properly.
  • @deconline1320
    Even though the goal here was to demonstrate Rust RAII mechanism, it's worth mentioning that modern C++ provides equivalent concepts using unique_ptr and moves. Nowadays, you rarely need to delete memory manually in C++.
  • @kadlubom
    Shouldn't the constructor be 'Bob' not 'Foo' though?
  • It’s worth noting that rust has type inference, so you don’t have to specify your type every declaration of a variable
  • @br3adina7or
    The reason you can't borrow mutably and immutably at the same time isn't because one function is expecting the data to be unchanging while another is expecting it to be mutable. If that was the case, as you are presenting, multiple mutable references would be allowed at the same time, when they very much aren't. Mutable references are meant to be exclusive so there's only ever one point of mutation for a given piece of data (and no immutable references at the same time), which is done in order to avoid data races and the such. This is why mutable references are often called exclusive references and immutable references are often called shared references. This principle is also applicable to `Rc`, which was mentioned. Rc basically gives shared references to the data, but it cannot be mutable; to have shared mutable data, one would have to use one of the interior mutability data structures (in the case of an `Rc`, you'd probably want a `RefCell`). I think it's important to make this clear when introducing the topic of references in Rust, because one of the core design principles is "fearless concurrency", and as such that is baked into its fundamental ownership principles. That is to say, these concepts are inherently tied in Rust. I don't know if this was an intentional simplification, but it's something that shouldn't've been omitted imo. As an aside, `Rc` and `Arc` aren't really like garbage collection. Like, they can be used like garbage collection, but basically instead of having a garbage collector go through the memory and seeing what should be dropped, `Rc` and `Arc` keep an internal counter and then increment it when cloned and decrement it when dropped. When an `Rc`/`Arc` is dropped and there's no more references, it just drops the underlying data. This means that using these smart pointers has a slightly different cost to the equivalent code in a garbage collected language. (Though this isn't really a major point.)
  • @GingerGames
    This video conflates RAII and ownership semantics quite a bit. This is a common misconception but if this is meant to be an introduction to either concept, this will most definitely confuse a newcomer to these concepts. You can explain Ownership Semantics without ever referring to RAII whatsoever and vice versa. Ownership semantics can be used to aid with a few issues that RAII in C++ causes (such as over use of copy constructors) but they solve different orthogonal problems entirely. C++11 onwards also has all of these ownership semantics (rvalue references, std::move, std::forward, etc), but they are an opt-in thing rather than something that is required like in Rust. Also, if you are wanting to reduce resource usage as much as possible, RAII is not the right tool for you and will most likely cause you to waste more memory than other approaches.
  • @mihir2012
    I think this was explained quite poorly. You can write as much garbage code in any language you want, including rust. What matters is that when you try to compile the code, the rust compiler rejects much more (memory related) garbage than the c/c++ compiler does. Whereas c/c++ will allow you to get to runtime and may or may not crash then, rust doesn't allow you to get to runtime at all until you have fixed these issues. And not once you showed any compiler output at all. Which is also probably why you kept using variables that don't exist at all.
  • @myronkipa2530
    Some of the things Rust does the right way: 1. RAII or memory ownership model - follow few rules and forget about memory leaks 2. Traits composition instead of trait inheritance. 3. Powerful enums/unions - can hold values. You have to consider all cases 4. Pattern matching 5. No NULL. Instead - enum with optional value 6. Powerful macros My main complaint with rust is that compiler won't let me be silly and write bad code. This also means it won't let you shoot yourself in the foot. But the learning curve is a bit steep. Rust is so different from other languages
  • @FalcoGer
    Your constructor and destructor for class Bob should be Bob and ~Bob, and not Foo and ~Foo. If you allocate an array with new, you need to use delete[] to clean that up, not just delete. In your rust code, you refer to bob when you variables are named n and b. Maybe you should get an IDE that highlights errors for you. Vim is great and all, just use syntastic or some other plugin to do that for you. Bare pointers are fine so long as it's simple and easy and there is no chance of accessing memory after it has been freed or it being very unlikely that you forget something. You should just use smart pointers instead otherwise. Unfortunately something that starts out simple can quickly grow in complexity and if you are not careful designing your API to your bob instances, someone might pull a pointer and use it outside some scope. Instead of trying to remember to allocate and clean up in two different spaces, you should just let the smart pointers handle that for you. They are well optimized. They do of course have their own drawbacks like cyclic dependencies that need to be watched out for, but generally they are the better choice. In your Bob example, a unique pointer would simply not work as you can't copy it without handing over ownership, and a shared pointer would work just fine, although you still wouldn't want to just return it like that as n probably makes no sense without bob. A weak pointer is probably the right choice here. If you want a fair comparison, then bob in c++ would also hold onto a high level structure, like std::vector, instead of a bare int[].
  • @konga8165
    Huge fan of Rust. I've been writing it in production for over a year now and it's been a dream to work with.
  • @zamf
    What wasn't mentioned is that the C++'s standard library is build around RAII and the notion of moving data around, so the concept is not new for Rust. Rust just enforces it by the compiler, while C++ lets you use RAII as well as unsafe resource management.
  • @h-0058
    Nice video, the Rust borrow checker is pretty cool, but the C++ comparison didn't make much sense. C++ has had smart pointers for 12 years now (maybe more with boost), which get rid of all the problems except dangling references. You never write new and delete in C++, you never use raw pointers that own memory, you can move or only "borrow". The only thing where standard C++ will not help you is if you borrow a pointer and try to access it after the owning pointer deleted the memory (so dangling references).