3 ms·
For the same reason that you don't use Rc for everything in Rust. Putting all your heap management behind reference counted pointers isn't "that inefficient",
by ajross 1y ago
For the same reason that you don't use Rc for everything in Rust. Putting all your heap management behind reference counted pointers isn't "that inefficient", no. But if you don't need the direct control over heap behavior, you shouldn't be using C++ (or Rust) in the first place.
Languages with GC-managed runtimes (Java, C#, Go, Swift, et. al.) are actually significantly more performant for almost all heap-bound use cases, actually. Reference counting kinda sucks for typical code.
- pjmlp 1y agoManual reference counting to be more precise. When a GC-managed language uses reference counting as implementation algorith, the compiler might be able to optimize the reference counting to only occur when it is unavoidable or too costly to reason about, in a similar vein to bounds checking. When using library types for reference counting, there is no way for the compiler to implement such optimizations, unless the types are somehow tagged with compiler intrisics so that they could apply the same kind of optimizations.
- ninkendo 1y ago> When using library types for reference counting, there is no way for the compiler to implement such optimizations Aren’t refcounts in shared_ptr done as part of the copy constructor and destructor? It seems like vanilla copy elision would count as optimizing away the refcounts.
- pjmlp 1y agoCopy constructor, destructor, move constructor, copy constructor. All of them have to do counter booking, value count and accessors, also possibly handle weak_ptr booking. Plus how it actually works isn't part of ISO C++, so you're betting your luck on how a specific C++ is actually going to implement it, and possible issues when compiler versions change, same compiler or to another one.
- ninkendo 1y agoC++17 has copy elision as part of the standard now, so you can be guaranteed of the scenarios where C++ is required to outright skip the copy/move/destruction, leaving no code paths left for any refcounts. It’s not everything, there’s still plenty of optimizations on the table, but copy elision should eliminate a ton of refcount bookkeeping.
- pjmlp 1y agoIn some scenarios, there is a reason why there a few conference talks on the gotchas regarding that, especially when coupled with RVO.
- ninkendo 1y ago> Languages with GC-managed runtimes (Java, C#, Go, Swift, et. al.) Swift does not have a GC managed runtime in the same sense as the other languages you listed [0], it’s basically a bunch of refcounts inserted by the compiler, with similar performance characteristics to Arc in Rust or shared_ptr in C++. (For classes, at least. Structs are value types and stack-allocated.) [0] Yes, automatic refcounting is a form of garbage collection, but Java/C#/Go use tracing GC’s and not direct refcounting, whereas with Swift it’s more like the compiler is wrapping all objects in a shared_ptr for you, and so destruction is explicit and happens at exact points.