According to my understanding, when a const shared_ptr& is upcasted, it creates a new shared pointer of the based class pointing to the same (casted) object.
#include <iostream>
#include <memory>
class Animal
{
};
class Cat : public Animal
{
};
void display(const std::shared_ptr<Animal>& animal)
{
std::cout << animal.use_count() << std::endl;
}
int main()
{
auto cat = std::make_shared<Cat>();
std::cout << cat.use_count() << std::endl;
display(cat);
std::cout << cat.use_count() << std::endl;
}
The output of the above code is as follow.
sujith@AKLJoincggDLEd:~/sujith$ g++ -std=c++17 main.cpp
sujith@AKLJoincggDLEd:~/sujith$ ./a.out
1
2
1
sujith@AKLJoincggDLEd:~/sujith$
My question is what operator does this? Can we get the same behaviour for other reference upcasting as well? Or is it speficially handled for shared_ptr references?
Thank you for looking into this.
The function that does this is std::shared_ptr
's constructor, specifically overload 9:
template< class Y >
shared_ptr( const shared_ptr<Y>& r ) noexcept;
These are the semantics:
Constructs a shared_ptr which shares ownership of the object managed by r. If r manages no object, *this manages no object either. The template overload doesn't participate in overload resolution if Y* is not implicitly convertible to (until C++17)compatible with (since C++17) T*.
Important is the last sentence. Your Cat*
(Y*) is convertible to / compatible with your Animal*
(T*). So, this constructor participates in overload resolution and is selected because it is the only one available (the other overloads do not match).
Here is a simplified example that highlights how the general concept works, that std::shared_ptr
uses in the quoted overload:
struct A{};
struct B {
B(A const& a) {}
};
void foo(B const&) {}
int main() {
A a;
foo(a);
}
The call to foo
implicitly creates a B
object via B::B(A const&)
. foo
is then passed a const reference to that temporary B
object.
The fact that in your example B
and A
were types stemming from the same class template is immaterial.