1

I got compile error when passing shared_ptr<Derived>& as shared_ptr<Base>&, see the below code and detailed question.

Note: this question is similar to "Passing shared_ptr<Derived> as shared_ptr<Base>" but not duplicate.

#include <memory> class TBase { public: virtual ~TBase() {} }; class TDerived : public TBase { public: virtual ~TDerived() {} }; void FooRef(std::shared_ptr<TBase>& b) { // Do something } void FooConstRef(const std::shared_ptr<TBase>& b) { // Do something } void FooSharePtr(std::shared_ptr<TBase> b) { // Do something } int main() { std::shared_ptr<TDerived> d; FooRef(d); // *1 Error: invalid initialization of reference of type ‘std::shared_ptr<TBase>&’ from expression of type ‘std::shared_ptr<TDerived>’ FooConstRef(d); // *2 OK, just pass by const reference FooSharePtr(d); // *3 OK, construct a new shared_ptr<> return 0; } 

Compiled by g++ -std=c++11 -o shared_ptr_pass_by_ref shared_ptr_pass_by_ref.cpp

Env: Ubuntu 14.04, g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

Detailed question: Why is it OK to pass by const reference (*2), but not OK to pass by reference (*1)?

Note: I know the best practice is to pass by const reference, but just want to know why the compile error occurs.

1
  • 1
    What if FooRef does b.reset(new TBase)? If the call were possible, you would end up with std::shared_ptr<TDerived> holding a TBase*. By the way, I suspect that FooConstRef call constructs a temporary that then binds to const reference; but temporaries can't bind to non-const ref. Commented Sep 19, 2014 at 2:57

1 Answer 1

4

You seem to expect some kind of template covariance, whereby AnyTemplateClass<Derived> can bind to AnyTemplateClass<Base>&. Templates don't work this way. Generally, AnyTemplateClass<Derived> and AnyTemplateClass<Base> are two distinct, completely unrelated classes.

A specific template class may, or course, provide a relationship in some form. shared_ptr<T> in particular has a templated constructor accepting shared_ptr<U> for any U such that U* is convertible to T*.

FooConstRef(d) call works by constructing a temporary - effectively

shared_ptr<TBase> temp(d); FooConstRef(temp); 

But temporaries can't bind to non-const references, that's why FooRef(d) doesn't work in a similar way.

Sign up to request clarification or add additional context in comments.

4 Comments

Great answer! But one more question, why the temporary of shared_ptr<TBase> can be created effectively? As long as it's a new shared_ptr, it still increase the use_count. Then is there any performance difference between FooConstRef() and FooSharePtr(), if we always pass shared_ptr<TDerived>?
"effectively" != "efficiently". In light of this fact, I'm not sure I quite understand your question. You seem to assume some meaning in my statement that I didn't place there.
Sorry for the unclear question, let me re-phrase: is there any performance difference between FooConstRef() and FooSharePtr(), if the passed parameter is shared_ptr<TDerived>? If I understand correctly, they have the same behavior, because both construct a temporary shared_ptr<TBase>, right?
No, I don't believe there's any difference, under given constraints.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.