Pracuję nad aplikacją dla kontrolera gromadzenia danych. Ma interfejs z wieloma innymi urządzeniami, co z kolei może zapewnić różne typy i ilości danych. W tym celu następujące hierarchia była opracowany (jest to trochę długi, ale pokrywa się ze mną):Bezpieczne przekazywanie odniesień do klasy abstrakcyjnej w C++
Podstawową jednostką informacji jest punkt odniesienia.
Datum
sama jest abstrakcyjną klasą , której potomkowie reprezentują różne typy [fizycznej] ilość: temperatura, ciśnienie, energia, moc, stan przekaźnika, itp. Każda instancja Datum reprezentuje pojedynczy odczyt (w pewnym momencie) .Dane są gromadzone przez
Device
s, które z kolei zawierają kilkaIO
s. Instancja Device przedstawia konkretne fizyczne urządzenie gromadzące dane; jego klasa ( potomek abstrakcyjnej klasyDevice
) reprezentuje model urządzenia, a zawiera cały specyficzny dla modelu kod niezbędny do połączenia się z nim i odczyty z niego odczytów z . Odbywa się to poprzez wywołanie funkcji wirtualnejvoid Device::update()
.Każda instancja
IO
reprezentuje zmienną, którą zbiera urządzenie. Na przykład: , jeśli urządzenie jest wielokanałowym monitorem temperatury, wówczas IO reprezentuje pojedynczy czujnik podłączony do urządzenia. IO można zapytać o wartość przez , wywołującIO::get_value()
, która zwracaDatum
.Wreszcie klasa
Node
przechowuje listę wszystkich urządzeń podłączonych do sterownika , innej listy wszystkich OI w tych urządzeniach, i zapewnia metody odpytywania wszystkich urządzeń na raz, poszczególne urządzenia, indywidualne iOS etc.
związki te są (nieco luźno) widoczne w następującym schemacie:
Obecnie dla samego problemu:
w tym wszystkim, wiele wystąpień potomków abstrakcyjnych klas muszą być przekazywane wokół i przechowywane przez cały czas: the węzeł przechowuje Device s i ich IO s, urządzenies sami przechowywania własnych IO s jako dobrze, danych uzyskać utworzone i wrócił i przeszedł wokół i zniszczone, urządzenie i lista IO zostanie zaktualizowane w miejscu, itd. Ale to nie jest jasne, jak wdrożyć wszystkie przechodząc wokół:
- przechodzące instancje klas abstrakcyjnych według wartości jest oczywiście wykluczone, a nawet to nie były abstrakcyjne, może to doprowadzić do obiektu krojenia.
- przekazywanie ich przez odniesienie działa dla argumentów funkcji, ale co z tworzeniem i zwracaniem instancji Datum? są tworzone jako zmienne lokalne w metodzie IO :: get_value, a więc są niszczone po powrocie. Ponadto nie jest możliwe przechowywanie referencji, np. w std :: map.
- wreszcie, przekazywanie wskaźników jest niebezpieczne. Aby zwrócić coś jako wskaźnik należy przydzielić pamięć w metodzie, a następnie wywołać funkcję dzwoniącego, aby zwolnić pamięć po tym, jak zwrócona wartość nie jest już używana. Poza tym, że jest to niewygodne, stwarza niebezpieczeństwo utraty przeciążenia pamięci, wykonanie podwójnej luki lub innej części programu, która usuwa teraz pusty wskaźnik, który wcześniej był tam przechowywany.
Więc jestem w rozterce, w jaki sposób można by realizować solidnego systemu wymiany obiektów, takich jak ten, z bardziej lub mniej niezawodnych sposobów zapewniających obiektów zachowywać jako zmienna przekazywane przez wartość (Pozostań tak długo, jak długo są potrzebne, ale nie dłużej), zachowując typowanie kaczkowe zapewniane przez dziedziczenie wspólnego interfejsu.
Dwa słowa: [smart pointers] (https://pl.wikipedia.org/wiki/Smart_pointer) – NathanOliver
Nie podoba się, że problemem jest "przemijanie". – juanchopanza
Myślę, że tylko konsument Datum będzie zainteresowany typem danych/urządzenia. W przeciwnym razie wszystkie elementy pośrednie będą po prostu przechodzić obok obiektów (które mogą i najprawdopodobniej będą klasami abstrakcyjnymi). Dlatego też, ponieważ punkt odniesienia powinien mieć wystarczającą ilość informacji, których konsument będzie oczekiwał. – sameerkn