3 ms·
shared_ptr certainly isn't, last I looked at it there was some significant performance overhead since it's required to be thread safe.
by vvanders 6y ago
shared_ptr certainly isn't, last I looked at it there was some significant performance overhead since it's required to be thread safe.
- gumby 6y agoYes but imagine writing thread safe refcounted GC in C. It’s painful and easy to forget some of the handshaking. Most of the abstractions (E.g. iterations) are zero cost as opposed to additional functionality like shared pointers or resizable vectors.
- pdpi 6y agoWhether shared_ptr are thread safe is an... interesting question. If you have to ask it the answer is “no”. At any rate, the definition of “zero cost” isn’t “it’s the same as a raw pointer”. Rather, it should be read as “its cost is the same as the equivalent functionality rolled by hand”. Shared_ptr implements a ref counting mechanism, which, absent a real GC, is necessary for actual shared ownership.
- vvanders 6y ago> To satisfy thread safety requirements, the reference counters are typically incremented using an equivalent of std::atomic::fetch_add with std::memory_order_relaxed (decrementing requires stronger ordering to safely destroy the control block). [1] That's why shared_ptr has horrible performance, the spec requires that the control block is thread-safe. Perf tanks due to the atomic load/stores. If you roll your own with a standard load/store you'll see significant performance increase which means it's definitely not zero-cost. This is why Rust explicitly went with Arc/Rc[2] so you don't have to pay that cost(although ambiguous ownership I would argue is a pattern you should try to eliminate anyway). [1] https://en.cppreference.com/w/cpp/memory/shared_ptr https://en.cppreference.com/w/cpp/memory/shared_ptr [2] https://doc.rust-lang.org/std/rc/struct.Rc.html https://doc.rust-lang.org/std/rc/struct.Rc.html / https://doc.rust-lang.org/std/sync/struct.Arc.html https://doc.rust-lang.org/std/sync/struct.Arc.html
- gpderetta 6y agoformally the answer to the question of "is shared pointer thread safe" is "no": modifying a shared pointer (for example by assigning to it) while another thread is reading (or writing) is UB (unless all accesses are done via the now deprecated std::atomic_* operations. It is true that the ref count is kept atomically, which allows accessing two distinct shared pointers that happen to point to the same object from different threads. This is pretty much a requirement to support the baseline distinct object thread safety (aka "as safe as int), but it is not what the unqualified "thread safe" normally refers to. /pedantic Anyway, it is true that with shared_ptr sometimes you might end up paying for what you do not use, but doing otherwise would have made any use of shared_ptr in threaded applications extremely unsafe so it was felt that in this case the cost was worth it for a vocabulary type object.
- virgilp 6y ago> At any rate, the definition of “zero cost” isn’t “it’s the same as a raw pointer”. Rather, it should be read as “its cost is the same as the equivalent functionality rolled by hand” What kind of definition is that? Zero cost is exactly that - 0 cost, the same performance as if you were not using the abstraction. The alternative to an abstraction is not "my hand-rolled implementation of said abstraction" - it is not using the abstraction, at all (but using lower-level mechanisms to achieve the same goal). 0-cost is used to tell people "you will still achieve the same performance by using the abstraction - and you gain additional benefits (safety, readability etc)". If I can get better performance with raw pointers, then smart pointers are not zero cost (it's still a good idea to use them instead of raw pointers! Just, let's stop pretending they are zero-cost)