avocado
avocado

Reputation: 2735

fail to pass shared_ptr<Derived> as shared_ptr<Base> reference

In the following code, I want to pass shared_ptr<Derived> as a shared_ptr<Base>& argument, but failed.

Error says,

cannot bind non-const lvalue reference of type 'std::shared_ptr<Base>&' to an rvalue of type 'std::shared_ptr<Base>'

so looks like I can only pass shared_ptr<Derived> as const argument, but this is not what I want to do, how to pass as non-const?

#include <iostream>
#include <memory>

class Base {
public:
  virtual void say() {
    std::cout << "I'm Base class" << std::endl;
  }
};

class Derived : public Base {
public:
  void say() {
    std::cout << "I'm Derived class" << std::endl;
  }
};

void foo(std::shared_ptr<Base>& obj) {
  obj->say();
}

int main() {
  auto base = std::make_shared<Base>();
  foo(base);

  auto derived = std::make_shared<Derived>();
  foo(derived);
}

Upvotes: 2

Views: 840

Answers (1)

lubgr
lubgr

Reputation: 38267

The issue is that std::shared_ptr<Derived> is implicitly convertible to std::shared_ptr<Base>, but that conversion results in a temporary object - which can't be bound to a non-const-qualified reference (as it's the case for foo's parameter).

That being said, it looks like foo has nothing to do with ownership. It's then preferred to pass parameters as references, not wrapped into a smart pointers (passing std::shared_ptr<T>& should only be done when a copy might be made from within a function, and if you always take a copy, just pass by value). For your examle:

void foo(Base& obj) {
  obj.say();
}

called like the following.

auto base = std::make_shared<Base>();
foo(*base);

auto derived = std::make_shared<Derived>();
foo(*derived);

Note the dereferencing of both shared pointer (*base and *derived). However, if a copy is intended, pass by value (which works when passing a temporary)

void foo(std::shared_ptr<Base> obj) {
  //                           ^^^ increases refcount
  obj->say();
}

and let the calling syntax as it is.

Upvotes: 4

Related Questions