Home > Back-end >  Cannot assign derived raw pointer to base unique_ptr
Cannot assign derived raw pointer to base unique_ptr

Time:01-26

I have some code that looks something this:

class Info {
  public:
    virtual bool IsHere() = 0;
    virtual std::wstring GetStr() = 0;
};

class WindowsInfo : public Info {
  public:
    virtual std::wstring GetAnotherStr() = 0;
    bool IsHere() override;
};

class AdvancedWindowsInfo : public WindowsInfo {
  public:
    AdvancedWindowsInfo() {}
    ~AdvancedWindowsInfo() {}

    std::wstring GetAnotherStr() override;
    std::wstring GetStr() override;
};
  
class InfoFactory {
  public:
    static Info* GetInfo();
};
  
class InfoManager {
  public:
    InfoManager();
    //~InfoManager();

    bool IsSomething();

  private:
    std::unique_ptr<Info> info;
};
  
InfoManager::InfoManager() {
  #if WIN
    info = std::make_unique<WindowsInfo>();
  #else  // currently no implementation Linux
    info = nullptr;
  #endif
}
  
bool InfoManager::IsSomething() {
    std::unique_ptr<Info> info = InfoFactory::GetInfo();

    return info && info->IsHere();
}
  
Info* InfoFactory::GetInfo() {
  #if IS_WINDOWS
    return new AdvancedWindowsInfo();
  #else
    return nullptr;
  #endif
}

The entire code is too large (and confidential) to post here, but this snippet sums it up pretty well.

Essentially, I have a base class and some derived classes.

I also have a manager that uses a (smart) pointer to that base class.

And a Factory Method that returns the appropriate Derived object (although the signature returns a Base*).

Unfortunately, I can't get the the assignment (via the Factory Method) to work. I've tried multiple approaches but nothing works.

I tried using unique_ptr and make_unique<raw pointer>() --> it doesn't work with derived classes, only base.

I tried using unique_ptr and raw pointers --> conversion is not possible.

I tried using raw pointers (although I don't want this) and raw pointers --> it tells me that the destructor is called on the base object which is abstract. How can you call a destructor when you haven't instantiated the object (since it's an abstract class)? The compiler is contradicting itself!

CodePudding user response:

Let's check the documentation for std::unique_ptr's constructors. The signature of the relevant constructor:

explicit unique_ptr( pointer p ) noexcept; (2)

The converting constructor that converts a raw pointer to a std::unique_ptr is explicit. Among other things, this means it cannot be used for copy initialization of the form

std::unique_ptr<Info> info = InfoFactory::GetInfo();

Instead, you can use direct initialization:

std::unique_ptr<Info> info{InfoFactory::GetInfo()};

Which will allow you to perform that conversion.


While looking at this code, however, I notice that the local variable info in InfoManager::IsSomething is shadowing the class member variable InfoManager::info. If you want to change an existing std::unique_ptr so that it's now managing a new raw pointer, you might want to use reset:

info.reset(InfoFactory::GetInfo());

CodePudding user response:

Ok, so I did the following:

  1. InfoFactory::GetInfo() now returns a std::unique_ptr<Info>, as indicated by Galik
  2. Added virtual ~Info() = default; as indicated by Nathan Pierson

Now everything seems to be working ok. For now, I will the question unanswered as I still need to run some tests and double check some things, but basically it seems to be ok.

Thank you to everyone who made positive contibutions!

  • Related