Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conversion from shared_ptr to weak_ptr polymorphism

I am having trouble getting around this one. Let's say I have this vector

std::vector<std::shared_ptr<Car>> cars; 

Car is an abstract class. I want to be able to return weak pointers of different types so I do the following.

template<typename T>
    std::weak_ptr<T> GetCar()
    {
        for (std::vector<std::shared_ptr<Car>>::iterator it = cars.begin(); it != cars.end(); ++it)
        {
            T* derived = dynamic_cast<T*>((*it).get());
            if (derived != nullptr)
            {
                std::weak_ptr<T> carPointer = *it;
                return carPointer;
            }
        }
        return std::weak_ptr<T>();
    }

I get the following error though when I try to use the function with a class that inherits from Car. Error C2440 'initializing': cannot convert from 'std::shared_ptr<Car>' to 'std::weak_ptr<Saab>' There might not be a valid car when asked for it. I tried using boost::optional but it does not handle polymorphism . I might go with raw pointers if I can't get this to work.

like image 904
miniconco Avatar asked Jul 07 '16 04:07

miniconco


1 Answers

You can't construct directly your weak_ptr<Saab> from the shared_ptr<Car> because the template parameter Car must implicitly be convertible to Saab in order to work.

But you can first convert your shared_ptr<Car> to shared_ptr<Saab> at first then construct your weak_ptr afterward. In my example below, I used the std::dynamic_pointer_cast to do it.

Here is what I came up with :

#include <iostream>
#include <vector>
#include <memory>

struct Car
{
    virtual void name() = 0;
};

struct Saab : Car
{
    virtual void name() { std::cout << "Saab" << std::endl; }   
};

struct Renault : Car
{
    virtual void name() { std::cout << "Renault" << std::endl; }   
};

template<typename T>
std::weak_ptr<T> GetCar(std::vector<std::shared_ptr<Car>> cars)
{
    for (std::vector<std::shared_ptr<Car>>::iterator it = cars.begin(); it != cars.end(); ++it)
    {
        auto derived = std::dynamic_pointer_cast<T>(*it);
        if (derived != nullptr)
        {
            std::weak_ptr<T> carPointer(derived);
            return carPointer;
        }
    }
    return std::weak_ptr<T>();
}

int main()
{
    std::vector<std::shared_ptr<Car>> cars;
    cars.push_back(std::make_shared<Saab>());
    cars.push_back(std::make_shared<Renault>());

    auto wp = GetCar<Saab>(cars);

    auto sp = wp.lock();
    if (sp)
    {
        sp->name();
    }

    auto wp2 = GetCar<Renault>(cars);

    auto sp2 = wp2.lock();
    if (sp2)
    {
        sp2->name();
    }

}

It prints out :

Saab

Renault

Coliru link : http://coliru.stacked-crooked.com/a/9dbb85b556b83597

like image 138
dkg Avatar answered Sep 23 '22 06:09

dkg