6 ms·
> Note that our use case is in a single-threaded context. Hence, the word safe should not be interpreted as ‘thread-safe.’ Single-threadedness greatly simplifie
by mwkaufma 1y ago
> Note that our use case is in a single-threaded context. Hence, the word safe should not be interpreted as ‘thread-safe.’ Single-threadedness greatly simplifies the design; we need not reason about race conditions such as one where an object is simultaneously moved and accessed on different threads. Extending the design to a thread-safe one is left as an exercise to the reader.
Why intentionally design a worse alternative to std::weak_ptr which has been around since C++11??
- TinkersW 1y agoThey never mention std::weak_ptr which makes me think they aren't aware of it.. yes this looks pretty useless and unsafe(isn't everything multi-threaded these days..)
- niekb 1y ago> isn't everything multi-threaded these days.. There are alternative ways to utilize a machine with multiple cores, e.g. by running one thread per CPU core, and not sharing state between those threads; in each such thread you then have single-thread "semantics".
- mwkaufma 1y agoweak_ptr supports this -- it's only mt-safe if you specialize it with std::atomic
- vlovich123 1y agoLast I checked weak_ptr is always atomic (ignoring weird attempted glibc magic when you don’t link against pthread)
- mwkaufma 1y ago? https://en.cppreference.com/w/cpp/memory/weak_ptr/atomic2 https://en.cppreference.com/w/cpp/memory/weak_ptr/atomic2
- vlovich123 1y agoOh sure, a single weak_ptr instance itself is not safe for multiple concurrent access of non-const methods. But weak_ptr -> shared_ptr reacquisition is atomic and all control block operations are: > Note that the control block used by std::weak_ptr and std::shared_ptr is thread-safe: different non-atomic std::weak_ptr objects can be accessed using mutable operations, such as operator= or reset, simultaneously by multiple threads, even when these instances are copies or otherwise share the same control block internally. The type T may be an incomplete type. There’s no variant of shared_ptr / weak_ptr that is non atomic in the standard library AFAIK.
- spacechild1 1y agoMulti-threading does not imply shared ownership, it can also be achieved with message passing.
- niekb 1y ago(Author here.) That is a good question. For our use case, we in fact do not use std::shared_ptr in our implementation, but instead a single-threaded shared_ptr-like class that has no atomics (to avoid cross-core contention). However, when I wrote the blog-post, I replaced that not-so-well-known class by std::shared_ptr for the sake of accessibility of the blogpost for a general c++ audience, but by doing so, it indeed becomes a natural question to ask why one wouldn't use std::weak_ptr (which I hadn't realised when writing the post). One reason why this design can still be beneficial when using the standard std::shared_ptr in its implementation, is when you do not want to manage the pointee object by a std::shared_ptr (which is a requirement if you want to use std::weak_ptr). E.g., if you want to ensure that multiple objects of that type are laid out next to each other in memory, instead of scattered around the heap. Another goal of the post is to show this idea, namely to use a shared_ptr<T*> (instead of shared_ptr<T>), which is kind of non-standard, but can be (as I hope I convinced you) sometimes useful.
- cherryteastain 1y ago> but instead a single-threaded shared_ptr-like class that has no atomics (to avoid cross-core contention Why would there be contention in a single threaded program?
- izabera 1y agoatomics aren't free even without contention. the slogan of the language is "you don't pay for what you don't use", and it's really not great that there's no non atomic refcount in the standard. the fact that it is default atomic has also lead people to assume guarantees that it doesn't provide, which was trivially predictable when the standard first introduced it.
- eMSF 1y agoRelated to this, GNU's libstdc++ shared_ptr implementation actually opts not to use atomic arithmetic when it infers that the program is not using threads.
- mabster 1y agoWe purposefully didn't use shared_ptr and hence weak_ptr. With these, it is all too easy to construct the "bad" version which has the stub reference count and pointer stored far away in memory from the object itself requiring a double dereference to access the object which is bad for cache performance. Instead we derived off a shareable class that has the reference count to make sure it is close in memory. We were happy to use unique_ptr, however.
- surajrmal 1y agoWith make_shared it's guaranteed to be a single allocation these days so you shouldn't necessarily have cache locality problems. I do think there are benefits to things being intrusively recounted as you save 8 bytes per object. And if you give up a weak count you can save even more.
- dataangel 1y agoThe atomics in std::weak_ptr are >20x more expensive even with 0 contention.