Jonathan Mee
Given these toy structs:
struct Foo {
virtual void Identify() const { cout << "Foo\n"; }
};
struct Bar : Foo {
void Identify() const override { cout << "Bar\n"; }
};
I'd like to create a `std::vector` of polymorphic objects. `std::vector<Foo>` suffers from [Object Slicing](https://en.wikipedia.org/wiki/Object_slicing) this can be avoided by maintaining a seperate `std::vector` of enums indicating the type which the element's dereference should be cast to. `std::vector<Foo*>` requires me to:
1. Maintain the objects in a separate `std::vector`
1. Dynamically allocate the objects with `new` which must be managed any time objects are removed from the `std::vector`
Does C++ provide me a way to have a polymorphic `std::vector` without me writing seperate support machinery?
Top Answer
Jonathan Mee
What you're looking for is smart pointers. C++ provides 2: [`std::unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr) and [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr). You'll want to make a `std::vector` of one of these.
`std::vector<std::unique_ptr<Foo>> unique` is preferable because it is very light weight, but elements cannot be copied, so you couldn't do these things with `unique`:
1. `unique.push_back(new Foo)` instead you'd have to do `unique.emplace_back(new Foo)`
1. `const auto element = unique.front()` instead you'd have to do `const auto& element = unique.front()`
1. `unique.push_back(unique.front())` instead you'd have to do `*unique.emplace_back(dynamic_cast<Bar*>(unique.front().get()) == nullptr ? new Foo : new Bar) = *unique.front()`
1. `const auto my_vec = unique` instead you'd need to write a function for copying these, something like:
```
std::vector<std::unique_ptr<Foo>> Copy(const std::vector<std::unique_ptr<Foo>>& rhs) {
std::vector<std::unique_ptr<Foo>> result;
for(const auto& i : rhs) {
*result.emplace_back(dynamic_cast<Bar*>(i.get()) == nullptr ? new Foo : new Bar) = *i;
}
return result;
}
```
Because we're using `dynamic_cast` to do [Run Time Type Identification (RTTI)](https://en.wikipedia.org/wiki/Run-time_type_information) the above code and that of **3** can balloon. This is an unfortunate cost of polymorphisim.
As far as `std::vector<std::shared_ptr<Foo>> shared`, this does not have any limitations upon copying elements. Thus RTTI need not be performed because the element itself is copied rather than recreated. Thus even though `std::shared_ptr` is heavier it is sometimes used in polymorphic `std::vectors`.