2

First of all, there are bunch of similar posts which appear like they are exactly the same issue, but I find that they are different from my problem. I am trying to use smart pointers for the first time in my C++ life. I have trouble making polymorphism with smart pointers. To be precise I am trying to convert the following raw pointers (line # 15 of code shown below) to smart pointers:

class Maze {
 public:
  Maze() = default;
  ~Maze() = default;
  void BuildStack(MobileRobot *&robot_in_maze);
};

class Target {
 public:
  Target() = default;
  ~Target() = default;
  void GoWheeled();
 private:
  Maze wheeledMaze;
  MobileRobot *wheeledRobotInMaze = new WheeledRobot();
};

class MobileRobot {
 public:
  MobileRobot() = default;
  MobileRobot(std::string RobotName);
  ~MobileRobot() = default;
  std::string name;
};

class WheeledRobot : public MobileRobot {
 public:
  WheeledRobot(): MobileRobot("Wheeled Robot") {};
  ~WheeledRobot() = default;
};

class TrackedRobot : public MobileRobot {
 public:
  TrackedRobot(): MobileRobot("Tracked Robot") {};
  ~TrackedRobot() = default;
};

void Maze::BuildStack(MobileRobot *&robot_in_maze) {}

void Target::GoWheeled() {
     wheeledMaze.BuildStack(wheeledRobotInMaze);
}

When I try to convert line no 15 of code to a shared pointer type shown below :

std::shared_ptr<MobileRobot> wheeledRobotInMaze = std::make_shared<WheeledRobot>();

I get the following error at line no 41 of code:

Non-const lvalue reference to type 'MobileRobot *' cannot bind to a value of unrelated type 'std::shared_ptr<MobileRobot>'

Why is this happening ?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Arun Kumar
  • 634
  • 2
  • 12
  • 26
  • 1
    The original code is incorrect, you should get an error message for `MobileRobot *wheeledRobotInMaze = new WheeledRobot();` because `WheeledRobot` has not been defined at that point. To improve the question please post a [Minimal, Complete and Verifiable Example](https://stackoverflow.com/help/mcve) that generates the error message you are asking about. – M.M May 12 '19 at 23:58
  • 2
    To fix the error message you will need to make some modification to the signature of `void Maze::BuildStack(MobileRobot *&robot_in_maze) {}` , since that function expects to receive a raw pointer by reference. However we cannot advise further without knowing what the function's requirements are – M.M May 13 '19 at 00:01
  • 1
    Please tag all [tag:c++14] questions as [tag:c++], also. You are instructed to do so in the tag wiki. This also allows the syntax highlighter to guess the syntax it should highlight with. I have made this change for you. I have also removed [tag:unique-ptr], as it doesn't seem to be mentioned anywhere in the question. – HTNW May 13 '19 at 00:02
  • @M.M my code is fairly complex and long (more than 800 loc). While creating this post I tried to create a [Minimal, Complete and Verifiable Example](https://stackoverflow.com/help/mcve) as much as possible... But there are some limitations... I cannot regurgitate lot of complex and long code.. Your suggestion about modifying the signature of `Maze::BuildStack(MobileRobot *&robot_in_maze) {}` now makes me think about something interesting. Thanks for that. – Arun Kumar May 13 '19 at 00:14
  • @ArunKumar Is that function taking an IN/OUT argument? – curiousguy Jun 11 '19 at 00:22
  • @curiousguy Please look at line #299 of [this](https://github.com/arunumd/ENPM809Y-Final-Project/blob/master/app/Maze.cpp) file. – Arun Kumar Jun 12 '19 at 01:55
  • @ArunKumar Why do you need the smart ptr? You can simply take a `MobileRobot&`. – curiousguy Jun 12 '19 at 05:05
  • @curiousguy That's correct ! – Arun Kumar Jun 13 '19 at 01:17

1 Answers1

2

std::shared_ptr<X> is not implicitly convertible to X*. So since BuildStack expects a raw pointer, it complains when you try to call it with a shared_ptr. You can either just get the raw pointer from the shared_ptr:

void Target::GoWheeled() {
     // this variable is only needed because BuildStack takes an lvalue reference
     // if you can change that, you don't need the variable
     MobileRobot* rawPtr = wheeledRobotInMaze.get();
     wheeledMaze.BuildStack(rawPtr);
}

Or, probably the better option since it's usually a good idea to consistently use shared_ptr instead of mixing it with raw pointers, you can change the signature of BuildStack to take a shared_ptr:

void Maze::BuildStack(std::shared_ptr<MobileRobot> &robot_in_maze) {}
Wutz
  • 2,246
  • 13
  • 15
  • The second suggestion works like a magic. You are a genius @Wutz :) – Arun Kumar May 13 '19 at 00:31
  • "_`std::shared_ptr` is not implicitly convertible to `X*`_" and if it was (which would be a defensible design choice), you still wouldn't be able to call `BuildStack`. To allow that for a smart pointer `p`, you would need an implicit conversion to `T*&`, which is technically possible by adding a member `operator T*&()` to some "smart pointer" `p`. But for an owning smart pointer, it would make no sense. The real Q is why does `BuildStack` need that reference for. **What's the contract?** – curiousguy Jun 11 '19 at 00:22
  • 1
    @curiousguy I know `"std::shared_ptr` is not implicitly convertible to `X*`". I came to know about it on May 13, 2019 when @Wutz pointed out. I refactored my code everywhere to have all relevant pointers as `std::shared_ptr`. My problems got fixed after doing this. – Arun Kumar Jun 12 '19 at 02:00