2014-11-10 3 views
16

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

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

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

+0

Вы пытались получить указатель на этот вектор? Как вы хотите определить тип броска, который вам понадобится? - Сделать все элементы в векторе, унаследованном от базового класса, такого как «IObject». В этом случае вы знаете, какой тип вектора и C++ позволяет безопасно использовать. – harper

+0

Не очень хорошая идея. – Ajay

+0

Да, но вы запрашиваете массив shared_ptr <>. Пара - это что-то другое и может быть полезно. – harper

ответ

22

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

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

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

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

+0

Спасибо. Так что нет способа сделать то, что я хочу, только с инструментами C++ 11? –

+2

Ну, вы могли бы попытаться реализовать решение для этого, но я думаю, что это будет очень полезно например, 'boost :: any'. Oh и' boost :: any' - функция повышения только заголовка, поэтому нет даже аргумента в том, что нужно ссылаться на дополнительную библиотеку. – JBL

+6

Собственно, что вы получите ее неопределенное Это показывает как segfault, если вам повезло. – sbi

27

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

/// 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.

+4

Обратите внимание, что этот подход работает только при условии, что вы можете ограничить типы, поддерживаемые вариантом во время компиляции. – bpw1621

+4

@bpw: Как бы вы поступили иначе? Вы не можете бросать (и это всегда сводится к кастингу на каком-то уровне) к типу, который вы не знаете во время компиляции. Единственный способ, которым я могу думать о типах, неизвестных во время компиляции, - это полиморфизм времени выполнения, который требует связанных типов. – sbi

5

Так же, как любой фундаментальный тип указателя конвертируемый в 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]); 

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

+21

Нет, это не то, что вы ищете. Объяснение через 'void *' плохое и приведет вас к написанию кода, который ___buggy, трудно исправить и трудно поддерживать___. Многие из конструкций C++ были изобретены именно для того, чтобы избавиться от этой старой привычки C. [sfrehse's answer] (http://stackoverflow.com/a/26844776/140719) - это лучше. – sbi

+3

Ну, я кое-что узнал. Не знал, что трюк был возможен. Конечно, теперь я должен убедиться, что я никогда, никогда не делаю что-то нехорошее в своем собственном коде. Satus - пожалуйста, слушайте всех, дающих понять, что это сломанный дизайн. Вы смешиваете идиоматический C с идиоматическим C++, и единственным результатом может быть хрупкий код. –

+0

@Satus Ну, я, конечно, рад, что я ошибся :-) – cmaster

Смежные вопросы