Unfortunately, like all of the talks at Going Native 2013, it was constrained by a very tight time schedule. Fortunately for us, though, Sean Parent gave a much more thorough talk last year at C++Now called Value Semantics and Concepts-based Polymorphism. It covers the same material and will probably answer your questions. I'll take a shot at explaining anyway....
Introduction
There are two types of semantics that a type can have:
- Value semantics.
- Reference semantics. (Sometimes called pointer semantics.)
It is possible to go on for many pages about how the two differ and when one is preferable to the other. Let's simply say that code using value types can be more easily reasoned about.
That is to say that nothing unpredictable happens at any point to an instance of a value type -- something that cannot be guaranteed with a reference type since the value that is referenced is shared between other parts of your code that hold a reference to it.
In other words: reference types are less predictable because they can be changed by a distant piece of code. For example, a function that you call could change the value referenced out from under you. Or, even worse, if threading is involved, the reference type could be changed at any time by another thread that happens to operate on the value referenced. For this reason, Sean Parent makes the statement that a shared_ptr
is as good as a global variable when it comes to being able to reason about code that uses one.
With all of that said, we should be prepared to answer the question at hand.
Question and Answer
For a value type T
, why does a shared_ptr<const T>
act like a value type even though it is a pointer type?
Because we cannot make changes to the const T
that is pointed to, everything that was said about pointer/reference types being less predictable no longer applies. We no longer have to worry about the T
being changed unexpectedly because it is a const value type.
If we did want to make a change to the T
, we would have to make a copy of it, leaving others that hold a shared_ptr<const T>
unaffected by our actions. Moreover, the copy can even be hidden inside a value type using a mechanism called Copy-on-write, which seems to be what Sean Parent ultimately did.
I think I've answered the question as Sean Parent would (and did in the linked C++Now presentation), but lets go a bit further with an addendum.....
A Big Addendum:
(Thanks to @BretKuhns for bringing this up and providing an example in the comments.)
There is one nagging thing wrong with this whole notion. Saying that shared_ptr<const T>
behaves like a value type is not necesarily correct unless we know that all living pointers/references to that instance of T
are const
. This is because the const
modifier is a one way street -- holding a shared_ptr<const T>
may prevent us from modifying the instance of T
, but does not prevent somebody else from modifying the T
through a pointer/reference to non-const
.
Knowing this, I would be weary of making the broad statement that shared_ptr<const T>
is as good as a value type unless I knew that all living pointers to it are const
. But, knowing such a thing requires global knowledge of the code around all usages of shared_ptr<const T>
-- something that would not be a problem for a value type. For that reason, it might make more sense to say something like: A shared_ptr<const T>
can be used to support value semantics.
On a side note, I was actually at Going Native 2013 -- maybe you can see the back of my head in the front left.