C ++ dotyczy własności pamięci - czyli semantyki własności .
Za zwolnienie tej pamięci odpowiada właściciel fragmentu dynamicznie przydzielanej pamięci. Tak więc naprawdę pojawia się pytanie, kto jest właścicielem pamięci.
W C ++ własność jest udokumentowana przez typ, w którym surowy wskaźnik jest zawinięty, więc w dobrym programie (IMO) C ++ bardzo rzadko ( rzadko , nie nigdy ) można zobaczyć surowe wskaźniki przekazywane dookoła (ponieważ surowe wskaźniki nie mają wywiedzionej własności, więc nie mów, kto jest właścicielem pamięci, a zatem bez uważnego przeczytania dokumentacji nie możesz powiedzieć, kto jest odpowiedzialny za własność).
I odwrotnie, rzadko można zobaczyć surowe wskaźniki przechowywane w klasie, każdy surowy wskaźnik jest przechowywany we własnym inteligentnym opakowaniu wskaźnika. ( Uwaga: jeśli nie jesteś właścicielem obiektu, nie powinieneś go przechowywać, ponieważ nie możesz wiedzieć, kiedy wyjdzie on poza zakres i zostanie zniszczony).
Więc pytanie:
- Z jakim rodzajem semantyki własności ludzie się spotykają?
- Jakie standardowe klasy są używane do implementacji tej semantyki?
- W jakich sytuacjach uważasz je za przydatne?
Pozwala zachować 1 typ własności semantycznej na odpowiedź, aby można było indywidualnie głosować w górę iw dół.
Podsumowanie:
Koncepcyjnie inteligentne wskaźniki są proste, a naiwna implementacja jest łatwa. Widziałem wiele prób implementacji, ale niezmiennie są one zepsute w sposób, który nie jest oczywisty dla zwykłego użycia i przykładów. Dlatego radzę zawsze używać dobrze przetestowanych inteligentnych wskaźników z biblioteki zamiast tworzyć własne. std::auto_ptr
lub jeden z inteligentnych wskaźników Boost wydaje się spełniać wszystkie moje potrzeby.
std::auto_ptr<T>
:
Właścicielem obiektu jest jedna osoba. Przeniesienie własności jest dozwolone.
Użycie: Pozwala to zdefiniować interfejsy, które pokazują wyraźne przeniesienie własności.
boost::scoped_ptr<T>
Właścicielem obiektu jest jedna osoba. Przeniesienie własności NIE jest dozwolone.
Użycie: używane do pokazania wyraźnej własności. Obiekt zostanie zniszczony przez destruktor lub po jawnym zresetowaniu.
boost::shared_ptr<T>
( std::tr1::shared_ptr<T>
)
Wielokrotna własność. To jest prosty wskaźnik liczony referencyjnie. Gdy liczba referencji osiągnie zero, obiekt zostanie zniszczony.
Użycie: Gdy obiekt może mieć wiele kwiatów, których okres istnienia nie może być określony w czasie kompilacji.
boost::weak_ptr<T>
:
Używane shared_ptr<T>
w sytuacjach, gdy może wystąpić cykl wskaźników.
Użycie: Służy do zatrzymywania cykli przed zachowywaniem obiektów, gdy tylko cykl utrzymuje wspólne odniesienie.
źródło
In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good (IMO)
Czy można to przeformułować? W ogóle tego nie rozumiem.In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good C++ program it is very rare to see RAW pointers passed around
. Wskaźniki RAW nie mają semantyki własności. Jeśli nie znasz właściciela, nie wiesz, kto jest odpowiedzialny za usunięcie obiektu.Istnieje kilka standardowych klas, które są używane do zawijania wskaźników (std :: shared_ptr, std :: unique_ptr itp.), Które definiują własność, a tym samym zdefiniuj, kto jest odpowiedzialny za usunięcie wskaźnika.Odpowiedzi:
Dla mnie te 3 rodzaje zaspokajają większość moich potrzeb:
shared_ptr
- liczone referencyjnie, zwalnianie, gdy licznik osiągnie zeroweak_ptr
- tak samo jak powyżej, ale jest to „niewolnik” dla ashared_ptr
, nie można cofnąć przydziałuauto_ptr
- gdy tworzenie i cofanie przydziału ma miejsce w ramach tej samej funkcji lub gdy obiekt należy traktować jako jedynego właściciela zawsze. Kiedy przypisujesz jeden wskaźnik do drugiego, drugi „kradnie” obiekt z pierwszego.Mam na to własną implementację, ale są one również dostępne w
Boost
.Nadal przekazuję obiekty przez odniesienie (
const
jeśli to możliwe), w tym przypadku wywołana metoda musi zakładać, że obiekt żyje tylko w czasie wywołania.Używam innego rodzaju wskaźnika, który nazywam hub_ptr . Dzieje się tak, gdy masz obiekt, który musi być dostępny z obiektów w nim zagnieżdżonych (zwykle jako wirtualna klasa bazowa). Można to rozwiązać, przekazując
weak_ptr
im a, ale samo to nie mashared_ptr
. Ponieważ wie, że te obiekty nie żyłyby dłużej niż on, przekazuje im hub_ptr (to po prostu opakowanie szablonu do zwykłego wskaźnika).źródło
noncopyable
i że prawa własności nie można przenieść.Prosty model C ++
W większości modułów, które widziałem, domyślnie zakładano, że otrzymywanie wskaźników nie otrzymuje własności. W rzeczywistości funkcje / metody rezygnujące z posiadania wskaźnika były zarówno bardzo rzadkie, jak i wyraźnie wyrażono ten fakt w swojej dokumentacji.
Ten model zakłada, że użytkownik jest właścicielem tylko tego, co wyraźnie przydzieli . Cała reszta jest automatycznie usuwana (przy wyjściu zakresu lub przez RAII). Jest to model podobny do C, rozszerzony przez fakt, że większość wskaźników jest własnością obiektów, które zwalniają je automatycznie lub w razie potrzeby (głównie przy zniszczeniu wspomnianych obiektów), a długość życia obiektów jest przewidywalna (RAII jest twoim przyjacielem, jeszcze raz).
W tym modelu surowe wskaźniki krążą swobodnie i przeważnie nie są niebezpieczne (ale jeśli programista jest wystarczająco inteligentny, użyje zamiast tego referencji, gdy tylko będzie to możliwe).
Model Smart Pointed C ++
W kodzie pełnym inteligentnych wskaźników użytkownik może mieć nadzieję, że zignoruje żywotność obiektów. Właścicielem nigdy nie jest kod użytkownika: jest to sam inteligentny wskaźnik (znowu RAII). Problem polega na tym, że odwołania cykliczne zmieszane z inteligentnymi wskaźnikami liczącymi referencje mogą być śmiertelne , więc musisz radzić sobie zarówno ze wspólnymi wskaźnikami, jak i słabymi wskaźnikami. Więc nadal masz własność do rozważenia (słaby wskaźnik może wskazywać na nic, nawet jeśli jego przewaga nad surowym wskaźnikiem polega na tym, że może ci to powiedzieć).
Wniosek
Bez względu na modele, które opisuję, chyba że wyjątek, otrzymanie wskaźnika nie oznacza otrzymania jego własności i nadal bardzo ważne jest, aby wiedzieć, kto jest właścicielem . Nawet w przypadku kodu C ++ w dużym stopniu wykorzystującego odwołania i / lub inteligentne wskaźniki.
źródło
Nie mają współwłasności. Jeśli tak, upewnij się, że jest to kod, nad którym nie masz kontroli.
To rozwiązuje 100% problemów, ponieważ zmusza cię do zrozumienia, jak wszystko na siebie oddziałuje.
źródło
Gdy zasób jest współdzielony między wieloma obiektami. Wzmocnienie shared_ptr korzysta z liczenia odwołań, aby upewnić się, że zasób zostanie cofnięty, gdy wszyscy zostaną skończeni.
źródło
std::tr1::shared_ptr<Blah>
jest często najlepszym rozwiązaniem.źródło
Od boostu jest też biblioteka kontenerów wskaźników . Są one nieco wydajniejsze i łatwiejsze w użyciu niż standardowy kontener inteligentnych wskaźników, jeśli będziesz używać obiektów tylko w kontekście ich kontenera.
W systemie Windows istnieją wskaźniki COM (IUnknown, IDispatch i friends) oraz różne inteligentne wskaźniki do ich obsługi (np. CComPtr ATL i inteligentne wskaźniki generowane automatycznie przez instrukcję „import” w programie Visual Studio na podstawie klasy _com_ptr ).
źródło
Gdy potrzebujesz dynamicznie alokować pamięć, ale chcesz mieć pewność, że zostanie ona zwolniona w każdym punkcie wyjścia z bloku.
Uważam to za przydatne, ponieważ można go łatwo ponownie osadzić i zwolnić bez martwienia się o wyciek
źródło
Nie sądzę, żebym kiedykolwiek mógł mieć współwłasność w moim projekcie. Właściwie z czubka głowy jedyny ważny przypadek, jaki przychodzi mi do głowy, to wzór wagi muszej.
źródło
yasper :: ptr to lekka alternatywa podobna do boost :: shared_ptr. Dobrze sprawdza się w moim (na razie) małym projekcie.
Na stronie internetowej http://yasper.sourceforge.net/ jest to opisane w następujący sposób:
źródło
Istnieje inna często używana forma pojedynczego-przenoszalnego właściciela, która jest lepsza,
auto_ptr
ponieważ pozwala uniknąć problemów spowodowanych przezauto_ptr
szalone zepsucie semantyki przypisania.Nie mówię o nikim innym niż
swap
. Każdy typ z odpowiedniąswap
funkcją może być pomyślany jako inteligentne odniesienie do jakiejś treści, której jest właścicielem do czasu przeniesienia własności do innej instancji tego samego typu, poprzez ich zamianę. Każda instancja zachowuje swoją tożsamość, ale zostaje powiązana z nową zawartością. To jak bezpieczne odniesienie do ponownego powiązania.(Jest to raczej inteligentne odniesienie niż inteligentny wskaźnik, ponieważ nie musisz jawnie usuwać go, aby uzyskać dostęp do treści).
Oznacza to, że auto_ptr staje się mniej potrzebne - jest potrzebne tylko do wypełnienia luk, w których typy nie mają dobrej
swap
funkcji. Ale wszystkie kontenery standardowe tak.źródło
Gdy twórca obiektu chce jawnie przekazać własność komuś innemu. Jest to również sposób dokumentowania w kodzie, który ci to daję i nie śledzę go już, więc upewnij się, że usunąłeś go po zakończeniu.
źródło