On Monday, 27 November 2017 at 20:13:35 UTC, Dmitry Olshansky
wrote:
I’ve seen a tech giant that works on uber high-performance
things making heavy use of STL, and being fond of C++14
“high-level” features.
Look, I am not against "high level" features, but shared_ptr is
nothing like the thread local ref-counting you were talking about
which was at least introduced by Walter and Andrei as a competing
solution to tracking of borrowed pointers in Rust.
That must be why you seriously have no idea how people use it.
Otherwise you’d know that nobody shares a reference to shared
pointer but rather a copy. The whole point of smart pointer is
to avoid naked references.
I have an idea of how people use it… why all the ad hominem?
I just don't find it very useful. In practice I'm usually better
off exchanging through a facade and having the exchanged resource
wrapped up in a custom type.
It is more maintainable and easy to deal with in terms of
correctness.
They are if you use them as intended - value types, that
pretend to be pointers.
Sure. Not that this is how they are defined to be used. It is a
very limited use case.
a shared control block is. (Technically you share a pointer,
not an object of type T, but that is a minor detail.)
No, you actually share an object and the last one to decrement
the ref will destroy it. Now that is actually thread-safe
thanks to atomic counter.
Ok, sure, you share an ownership relation to an object, but it
isn't general enough, which was what I tried to suggest. For
instance, if you have a resource on a GPU with an integer ID that
is also a resource, but shared_ptr does not work (unless you
accept extra indirections).
So, I'd rather see an owned<T>, which also can handle
non-pointed-to-objects. Then one might ask, why not just have
"unique<owningptr<T>>" or "shared<owningptr<T>>" that also would
work with "unique<Resource>" and "shared<Resource>"?
Then you can build generic ADTs with a generic notion of
ownership .
The basic idea is that an owned resource that has to go through a
pointer isn't really necessary or as generic a type as it could
have been.
That is my original point, which you now violently agree with :)
Ok, then I didn't get your original point.
Just underlines that you don’t understand how it is supposed to
be used.
I know how it can be used. That doesn't mean that it is as
generally useful as it should be to be useful for what I want to
do.
I also don’t understand what are you trying to prove. My point
was: C++ has to do atomic counting, because it has no concept
of shared vs local.
That I disagree with. In C++ correct syncing is entirely
dependent on the programmer. Even if atomic_shared_ptr provide
some guarantees these guarantees will not hold if you depend on
more than one entity. So there is no mechanism in C++ that
provide something to ensure correctness when it comes to
concurrency. I.e. you totally depend on the programmer's ability.
You can create a concept of D-style local/shared by just creating
a wrapper type and use a lint-style verification. This is the
route C++ is heading in general for various properties related to
pointer types it seems. (e.g. wrap with borrowed, owned, nullable
etc).
Which is also basically what D has, except shared is a builtin,
but semantically I see no difference. To get a semantic
difference that matter you need concurrency to be part of the
language itself. If you cannot express propositions about
concurrency in the language, then there is a very limited ability
to do something interesting with it.
You did imply it’s useless on single thread and not used in
concurrency because you need manual sync. I’d argue you don’t
need a sync to access shared_ptr, you’d need it for object it
points to.
Listen, if you build a shared graph with shared_ptrs then you are
in trouble. So you would need atomic_shared_ptrs. That's a
perfectly reasonable use case.
You are presuming that the shared_ptr objects are thread local
and that they are not embedded in other objects that are
reachable by another thread.
Those a very limiting presumptions.
It still solves the ownership and deterministic destruction in
the presense of concurrent shared_ptrs of the same object.
But it doesn't solve correctness. You still rely on the
programmer to get correctness. Which is a tall order when you use
encapsulation.
That only works if you never embed shared_ptr in a class.
Copy & destruction is actually fine, which you seem to ignore.
Also accessing const methods of payload is fine. New C++
implies const == thread safe btw, at least in all of STL.
As far as I can see from the description at cppreference.com
there is no guarantee of freedom for races for anything if both
threads reference the same shared_ptr object (not the control
block but the object pointing to the control block).
You can obviously transmit it to another thread using a
mutex-like/messaging-like setup if that is what you mean.