3

Is there analogy between Rust smart pointers std::rc::Rc and std::sync::Arc with the C++ smart pointers std::shared_ptr and std::atomic_shared_ptr? For me, they look the same, but probably there are some implementation nuances. For example in C++ std::shared_ptr the reference count in the control block is atomic despite the pointer itself is not. Is it the same in Rust's std::rc::Rc?

bobeff
  • 3,543
  • 3
  • 34
  • 62
  • 3
    It doesn't look like `atomic_shared_ptr` was ever made part of `std`; it [lived in `experimental`](https://en.cppreference.com/w/cpp/experimental/atomic_shared_ptr) until it was [standardized as a specialization of `std::atomic>`](https://en.cppreference.com/w/cpp/memory/shared_ptr/atomic2). Does that help answer the question or would you like to rephrase it in light of this fact? – trent Apr 12 '21 at 18:53

2 Answers2

11

Rust's Arc<T> is largely equivalent to C++'s shared_ptr<T>

Both are "smart pointers" that provide shared ownership of a value via reference counting. They both use atomics for internal operations so that ownership can be tracked between threads safely.

One notable difference is the C++ std::shared_ptr implementation provides an aliasing constructor where you can create a std::shared_ptr<U> for a nested field of a std::shared_ptr<T> such that the std::shared_ptr<U> tracks the root T object properly.

C++ has no equivalent of Rust's Rc<T>

The only difference between std::rc::Rc and std::sync::Arc is that the internal reference tracking is not atomic. This means it cannot be used between threads, but has the benefit of avoiding the potential costs of atomic operations.

Rust has no equivalent of C++'s atomic<shared_ptr<T>>

C++'s std::atomic is generic so its atomic pointer type is a std::atomic<T*> whereas Rust's just has the dedicated type std::sync::atomic::AtomicPtr<T>. C++ has a specialization for std::atomic<std::shared_ptr<T>> so that multiple threads can atomically access and modify the shared_ptr itself, not just the shared value. The std::atomic_shared_ptr mentioned by OP was not standardized in favor of this specialization.

There may exist libraries for the equivalents but I've only included what's in the respective standard libraries.

See also:

kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • 2
    When considering whether Rust has an "equivalent" of `atomic>`, it may be worth noting that `atomic>` exists on every platform, but is not guaranteed to be lock-free, while [`AtomicPtr` is always lock-free, but not guaranteed to exist on every platform](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html). There is a crate (`atomic` IIRC) that provides an `Atomic` type constructor with C++-like semantics. – trent Apr 12 '21 at 19:39
  • @trentcl I could be here all day recounting the things like "`shared_ptr` is safe between threads but that doesn't mean `T` is safe between threads whereas Rust's type system ensures that", or C++ has *these* functions but Rust has *these*, or mentioning as you have about how the standard library chooses to provide cross-platform support. I tried my best to give a big picture overview of the differences since that seemed to be the focus of the question. – kmdreko Apr 12 '21 at 19:51
  • 1
    Understood. My comment wasn't meant as a criticism of your answer (or of C++), more "fun fact" than anything. – trent Apr 12 '21 at 19:56
2

For example in C++ std::shared_ptr the reference count in the control block is atomic despite the pointer itself is not. Is it the same in Rust's std::rc::Rc?

No. Arc is the analogue to shared_ptr: the reference-counting is atomic (and thus thread-safe), the data is not (which is why you'll usually see Arc<Mutex<T>> or Arc<RwLock<T>> in order to allow mutation of the inner type, otherwise Arc will only provide read-only access).

Rc is completely unsynchronised, and in fact statically can not be moved between threads (it's !Send). There is no such type in the C++ standard library[0].

[0] although libstdc++ will use non-thread-safe shared_ptr if it believes multithreading is not involved, that's more of an optimisation / hack: https://snf.github.io/2019/02/13/shared-ptr-optimization/

Masklinn
  • 34,759
  • 3
  • 38
  • 57