2 ms·
Maybe, but in the example functions have only one argument with a pointer, so there cannot be any aliasing. And there is no need for locks because there is no p
by codedokode 4y ago
Maybe, but in the example functions have only one argument with a pointer, so there cannot be any aliasing. And there is no need for locks because there is no pointers shared between threads.
- maemre 4y agoI think the answer is a combination of both and inlining. With Rc, the compiler can inline the reference count increment/decrements as well as the non-public function add_numbers and the surrounding code is simple enough that it can do dead code elimination as well as other optimizations to remove the unobservable behavior. If you switch to use Arc (which is a better equivalent of shared_ptr as it also does locking/unlocking), the generated code is more comparable (funnily enough, part of the code for drop in Arc is deliberately not inlined so it prevents this optimization [1]). Also, if one makes add_numbers public, the generated code is much larger. I don't know why the compiler chooses not to inline it in this case, probably (really speculating here) because it can be called in multiple locations and the IR for the function is over the inlining budget. [1]: https://doc.rust-lang.org/src/alloc/sync.rs.html#1088 https://doc.rust-lang.org/src/alloc/sync.rs.html#1088
- db48x 4y agoBut someone could come along in six months and make a pointer to one of those fields, which would be an alias and would simultaneously allow mutation. The C++ language allows that, and so the C++ compiler must be very careful about optimizations. Meanwhile in Rust if someone added the same kind of reference then the compiler would force it to be immutable (trying to create a mutable reference would cause a compiler error). Mutating the field would require that some part of the code own the value, not just own an Rc with a reference to the value inside of it. In Rust you can have mutability _or_ you can have multiple aliases, but not both at the same time. Thus the Rust compiler is free to make optimizations the C++ compiler cannot. (But you’re right about the specific program here; it’s too simple for aliasing and mutability to really matter; I was just answering the general question.) Also, if someone passed this Rc along to another thread then they would also get a compile error. If they really need to do that then they can make the jump to the Arc type, which is thread–safe, and then the compiler will allow it. But they can never make the mistake of sending an un–thread–safe value to another thread where it will cause race conditions, data corruption, etc.
- steveklabnik 4y agoAs time has gone on, “if someone comes along in six months” so to me, a fantastic reason to use Rust. These things can feel onerous at first, but the pain it saves you later is wild. Niko has an anecdote about how he had an Rc<T> somewhere deep in a program, and later he came back and added in threads, and the compiler was like “oh no! You gotta fix that first!” and that would be a latent bug in 99% or programming languages. Humans are fallible, but compilers don’t forget.