Массив общих указателей на разные классы

Я пытаюсь выяснить, возможно ли создать массив общих указателей для разных типов. Например, что-то вроде этого:

vector<shared_ptr<**???**>> v;
v.push_back(shared_ptr<int>(new int));
v.push_back(shared_ptr<MyClass>(new MyClass()));

или любым другим способом передать shared_ptr, не зная его типа.

Ответы

Ответ 1

Более безопасный тип может быть:

/// header #include <boost/variant.hpp>
typedef boost::variant < boost::shared_ptr < T1 >, boost::shared_ptr < T2 >, ... > VariantT;

std::vector < VariantT > container;
container.push_back ( boost::shared_ptr < T1 > ( new T1 ) ); // or boost::make_shared
container.push_back ( boost::shared_ptr < T2 > ( new T2 ) ); // or boost::make_shared

Подробнее рассмотрите Boost.Variant library.

Ответ 2

Предполагая, что вы хотите хранить объекты, которые не наследуют общий класс, самым простым способом, который приходит на ум, является использование boost::any.

Вы все же должны быть уверены в том, какой тип каждого объекта хранится в каждом индексе (т.е. иметь возможность выполнить правильное boost::any_cast).

Вы должны сделать это, а не сохранить указатели на void. Это ближе всего к семантически правильному способу хранения "того, что вы знаете, типа, но компилятор не делает", подразумевая приведение при извлечении значения.

В то время как оба указателя (any и a void) будут работать одинаково (указатель в сторону), если вы используете неверный тип, any будет генерировать исключение bad_any_cast (IIRC), в то время как указатель void, вы получите поведение undefined. Простая попытка на coliru дала segfault.

Ответ 3

Так же, как любой основной тип указателя преобразуется в void*, любой shared_ptr преобразуется в shared_ptr<void>:

vector<shared_ptr<void>> v;
v.push_back(make_shared<int>());
v.push_back(make_shared<MyClass>());

Теперь у вас есть vector полностью разделенных стилями общих указателей. Однако вы ничего не можете сделать с этим интересным: вам нужно как-то узнать, какие типы хранятся в слотах vector для их преобразования:

auto intptr = static_pointer_cast<int>(v[0]);
auto myclass_ptr = static_pointer_cast<MyClass>(v[1]);

Итак, хотя это можно сделать, это не очень полезно и, вероятно, указывает на сломанный дизайн.