Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polymorphism : raw pointer vs smart pointer

how makes this work ?

I want to use a vector of multiple types (research, add, delete) for an inventory management (Potions, Weapons, etc.. all derived from virtual class Item).

I simplify the problem here : I have a vector containing Item (Base class) and Weapons (Derived class). For memory management issues, i prefered using unique_ptr but didn't a way to return it or use it properly.

Example Below :

// UniquePointerAndPolymorphism.cpp : Ce fichier contient la fonction 'main'. L'exécution du programme commence et se termine à cet endroit.
//

#include <iostream>
#include <vector>

class Item
{
protected:
    std::string name_;
public:
    Item(std::string name) :name_(name) {};
    virtual std::string getName() { return "b_" + name_; };
};


class Weapon : public Item
{
public:
    Weapon(std::string name) : Item(name) {};
    std::string getName() override { return "d_" + name_; };
};

std::vector<std::unique_ptr<Item>> elements;

std::unique_ptr<Weapon> getAnElement_uniquePointer(int i)
{
    /*
     *
     * How to return unique pointer from the vector ?????
     *
     */
    return std::make_unique<Weapon>("returned");

}

Weapon* getAnElement_rawPointer(int i)
{
    if (auto oneElement = dynamic_cast<Weapon*>(elements[i].get()))
    {
        return oneElement;
    }
    else
    {
        return nullptr;
    }
}


int main()
{

    elements.push_back(std::make_unique<Weapon>("1"));
    elements.push_back(std::make_unique<Item>("2"));
    elements.push_back(std::make_unique<Weapon>("3"));

    Weapon* rptElement = getAnElement_rawPointer(2);
    std::cout << rptElement->getName() << std::endl;

    std::unique_ptr<Weapon> uptElement = std::move(getAnElement_uniquePointer(0));
    std::cout << uptElement->getName() << std::endl;

}

So I have a few questions :

  • Even if it seems to not be the problem, is Polymorphism compatible with smart pointers ?
  • Was returning a raw pointer the only solution ?
  • Do I have to use shared_pointer to use it in the vector and in another part of my programm ?
  • Is there a way to return a reference ?

Thanks. Sebastien

like image 480
Studio Albert Avatar asked Nov 20 '25 18:11

Studio Albert


1 Answers

Even if it seems to not be the problem, is Polymorphism compatible with smart pointers ?

Yes, polymorphism is compatible with smart pointers.

Was returning a raw pointer the only solution ?

No, returning a raw pointer is not the only solution. (See optional reference answer below.)

One convention is to use raw pointers to indicate a non-owning pointer.

Unfortunately, it isn't often clear that the intent is for raw pointers to be non-owning pointers, because historically raw pointers are often owning pointers.

You would need to adhere to a discipline of raw pointers are non-owning pointers if you adopt such a policy. (I think it is a good policy, and I use it.)

Do I have to use shared_pointer to use it in the vector and in another part of my program?

No, you do not have to use a shared_ptr. Using a shared_ptr is federated ownership.

Federated ownership is tantamount to being a global variable. Unless the object is immutable, reasoning about the object state is tricky, especially if different owners have different invariants.

I consider using a shared_ptr a last resort. My go to smart pointer is a unique_ptr (and raw pointers as non-owning).

Is there a way to return a reference?

Yes, you could return a reference to a Weapon.

Weapon& getAnElement_reference(int i) {
    if (auto oneElement = dynamic_cast<Weapon*>(elements[i].get()))
    {
        return *oneElement;
    }

    throw std::logic_error("No weapon");
}

But what to do if the index refers to an object that is not a Weapon? The code would need to throw an exception.

An alternative to throwing an exception is to return a std::optional<std::reference_wrapper<Weapon>> which could be a std::nullopt_t when there is no Weapon at that index. Then the caller needs to access the optional explicitly.

That would also be safer than a raw pointer if the caller neglects to check for nullptr, which is an easy mistake to make and the compiler won't help catch those mistakes.

like image 138
Eljay Avatar answered Nov 23 '25 09:11

Eljay



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!