Search code examples
c++c++20stdvectorsmart-pointers

Vector of Base Shared Pointers to Vector of Derived Shared Pointers


I have a class Base:

class Base
{
};

and a derived class Derived:

class Derived: public Base
{
};

Now I need to get a vector of Derived Pointers:

std::vector<std::shared_ptr<Derived>> derivedVec;

but they are stored unfortunately as a vector of Base Pointers, e.g. I can access only the downcasted pointers:

std::vector<std::shared_ptr<Base>> baseVec;

How to I perform the conversion from std::vector<std::shared_ptr<Base>> to std::vector<std::shared_ptr<Derived>>. The solution is desired to be C++20 style.


Solution

  • Firstly, two vectors std::vector<A> and std::vector<B> aren't covariant, meaning that it's not enough to reinterpret one as the other. To get a std::vector<std::shared_ptr<Derived>>, you need to convert the vector:

    #include <vector>
    #include <memory>
    #include <ranges>
    
    // ...
    
    std::vector<std::shared_ptr<Base>> base;
    auto derived_view = base | std::views::transform([](const std::shared_ptr<Base> &b) {
        // or use std::dynamic_pointer_cast for polymorphic classes
        return std::static_pointer_cast<Derived>(b);
    });
    
    // If you don't need to create a new vector, but just want to examine the old one
    // with the conversion applied, you can also skip this step and work with the view.
    std::vector<std::shared_ptr<Derived>> derived(derived_view.begin(), derived_view.end());
    
    // In C++23, you can also write:
    std::vector<std::shared_ptr<Derived>> derived(std::from_range, derived_view);
    // however, not every standard library supports this yet, at the time of writing
    

    See live example at Compiler Explorer