To me, it looks like an implementation of std::shared_ptr
which stores a reference counter in a static std::unordered_map<void*, struct Counters>
would be much more simpler and also allow us to avoid some dirty workarounds like std::enable_shared_from_this
(because std::shared_ptr<T>{this}
wouldn't create new control block, only increment a counter for a pointer that already exists in a map).
So why does a committee decided to stick with a control block implementation?
CodePudding user response:
So why does a committee decided to stick with a control block implementation?
It doesn't. The committee writes requirements that implementers must follow. They do not specify that std::shared_ptr
be implemented in any particular way, so long as that way meets the requirements.
Having said that, your proposed static std::map<T*, size_t>
runs foul of this general (unless otherwise specified) requirement:
A C standard library function shall not directly or indirectly access objects ([intro.multithread]) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function's arguments, including
this
.
Another compelling reason is that std::shared_ptr
type-erases the deleter, so at best you'd have a static std::map<void *, struct { size_t count; size_t weak_count; std::function<void(void*)> deleter; }>
, at which point you have two dynamic allocations for the control block, rather than the one (possibly merged with the owned object) that current implementers prefer.