2014-11-10 14 views
16

Próbuję dowiedzieć się, czy jest możliwe utworzenie tablicy współdzielonych wskaźników dla różnych typów. Na przykład coś takiego:Tablica współdzielonych wskaźników do różnych klas

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

lub w inny sposób przekazać shared_ptr, nie znając jego typ.

+0

Czy próbowałeś pobrać wskaźnik z tego wektora? Jak chcesz wykreślić typ, którego będziesz potrzebować? - Uczyń wszystkie elementy w wektorze odziedziczonym po klasie bazowej, na przykład "IObject". W takim przypadku znasz typ wektora, a C++ pozwala ci bezpiecznie rzucać. – harper

+0

Niezbyt dobry pomysł. – Ajay

+0

Tak, ale pytasz o tablicę shared_ptr <>. Para jest czymś innym i może być przydatna. – harper

Odpowiedz

22

Zakładając, że chcesz przechowywać obiekty, które nie dziedziczą wspólnej klasy, najprostszy sposób, jaki przychodzi Ci na myśl, to użycie boost::any.

Nadal musisz być pewien, jaki jest typ każdego obiektu przechowywanego w każdym indeksie (tj. Aby móc wykonać poprawną boost::any_cast).

Powinieneś to zrobić zamiast przechowywać wskaźniki do void. Jest to najbliższy dostęp do semantycznie poprawnego sposobu przechowywania "czegoś, co znasz typ, ale kompilator nie", co oznacza rzutowanie podczas pobierania wartości.

Choć obie (any i void wskaźnik) będzie działać w ten sam sposób (wskaźnik na bok), jeśli oddanych do niewłaściwego typu, any wygeneruje bad_any_cast wyjątek (IIRC), natomiast ze wskaźnikiem void, będziesz uzyskać niezdefiniowane zachowanie. Prosta próba na coliru przyniosła a segfault.

+0

Dzięki. Więc nie ma sposobu robienia tego, co chcę za pomocą tylko narzędzi C++ 11 –

+2

Cóż, możesz spróbować zaimplementować rozwiązanie do tego, ale myślę, że skończy się bardzo jak 'boost :: any' i tak Oh i' boost :: any' jest funkcją tylko nagłówkową doładowania, więc nie ma nawet argumentu konieczności połączenia z dodatkowymi bibliotekami. – JBL

+6

W rzeczywistości, co otrzymasz nieokreślone To pokazuje jako segfault _if masz szczęście. – sbi

27

Więcej typ bezpieczny może być:

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

Więcej spojrzeć na Boost.Variant library.

+4

Należy zauważyć, że to podejście działa tylko pod warunkiem, że można ograniczyć typy, które dany wariant obsługuje podczas kompilacji. – bpw1621

+4

@bpw: Jak postąpiłbyś inaczej? Nie można rzutować (a to zawsze sprowadza się do rzucania na pewnym poziomie lub innym) do typu, którego nie znasz podczas kompilacji. Jedyny sposób, w jaki mogę poradzić sobie z typami nieznanymi podczas kompilacji, to polimorfizm runtime, który wymaga powiązanych typów. – sbi

5

Podobnie jak każdy typ podstawowym wskaźnikiem jest zamienny do void* każdy shared_ptr przekonwertuje do shared_ptr<void>:

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

Masz teraz vector w pełni wpisać-wymazane wskaźniki wspólne. Nie można zrobić niczego ciekawego z nim, ale: trzeba by jakoś wiedzieć, jakiego rodzaju są przechowywane w jakich szczelin vector konwertować je z powrotem:

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

Więc chociaż jest to możliweaby to zrobić, nie jest to zbyt użyteczne i prawdopodobnie jest oznaką zepsutego projektu.

+21

Nie, to nie jest to, czego szukasz. Generyczność poprzez 'void *' jest zła i poprowadzi cię do napisania kodu, który ___buggy, trudny do naprawienia i trudny w utrzymaniu___. Wiele konstrukcji C++ zostało wynalezionych dokładnie po to, aby pozbyć się tego starego habitatu C. [Odpowiedź sfrehse] (http://stackoverflow.com/a/26844776/140719) jest o wiele lepszy. – sbi

+3

Cóż, nauczyłem się czegoś tutaj. Nie wiedziałem, że to możliwe. Oczywiście, muszę teraz upewnić się, że nigdy, przenigdy nie zrobię czegoś tak dziwnego w moim własnym kodzie. Satus - proszę posłuchajcie wszystkich, dając do zrozumienia, że ​​to zepsuty projekt. Mieszacie idiomatyczne C z idiomatycznym C++, a jedynym rezultatem może być delikatny kod. –

+0

@Satus Cóż, z pewnością cieszę się, że się myliłem :-) – cmaster

Powiązane problemy