If I want to use shared_ptr
polymorphically, why is std::shared_ptr<A>& ptr
not working? However, const std::shared_ptr<A>& ptr
works fine.
class A {
public:
virtual void foo() { std::cout << "A" << std::endl; }
};
class B : public A {
public:
void foo() override { std::cout << "B " << std::endl; }
};
void working(const std::shared_ptr<A>& ptr) {
ptr->foo();
}
void not_working(std::shared_ptr<A>& ptr) {
ptr->foo();
}
int main() {
auto ptr = std::make_shared<B>();
working(ptr);
not_working(ptr); // <-- compilation error
return 0;
}
After compiling, I get the following compilation error:
main.cpp: In function ‘int main()’:
main.cpp:44:16: error: cannot bind non-const lvalue reference of type ‘std::shared_ptr<A>&’ to an rvalue of type ‘std::shared_ptr<A>’
44 | notworking(ptr);
| ^~~
In file included from /usr/include/c++/11/memory:77,
from main.cpp:2:
/usr/include/c++/11/bits/shared_ptr.h:296:9: note: after user-defined conversion: ‘std::shared_ptr<_Tp>::shared_ptr(const std::shared_ptr<_Yp>&) [with _Yp = B; <template-parameter-2-2> = void; _Tp = A]’
296 | shared_ptr(const shared_ptr<_Yp>& __r) noexcept
| ^~~~~~~~~~
main.cpp:32:37: note: initializing argument 1 of ‘void notworking(std::shared_ptr<A>&)’
32 | void notworking(std::shared_ptr<A>& ptr) {
| ~~~~~~~~~~~~~~~~~~~~^~~
make: *** [<builtin>: main] Error 1
shared_ptr<A>
and shared_ptr<B>
are distinct and unrelated types. B
deriving from A
does not make shared_ptr<B>
derive from shared_ptr<A>
.
Since B
derives from A
, there is an implicit conversion from B*
to A*
, and so the compiler is allowed to assign a shared_ptr<B>
object to a shared_ptr<A>
object, and they will both be pointing at the same B
object.
When calling working()
, the compiler has to create a temporary shared_ptr<A>
object from the shared_ptr<B>
object. And since a const reference can bind to a temporary, this works as expected.
When calling not_working()
, the compiler still has to create a temporary shared_ptr<A>
object. But, since a non-const reference cannot bind to a temporary, you get the error.