2010-11-21 16 views

Odpowiedz

12

pierwsze kilka korekt do pytania:

  • scoped_ptr jest częścią Boost, i nie jest wliczone w obu C++ TR1 lub C++ 0x (oczekuje się, że w C++ 0x unique_ptr można używać tam, gdzie tradycyjnie używane jest scoped_ptr).

  • unique_ptr nie jest częścią C++ TR1; jest częścią C++ 0x (ponieważ bazuje na odwołaniach rvalue i semantykach przeniesienia, które są dostępne tylko w C++ 0x).

Aby odpowiedzieć na to pytanie: shared_ptr i weak_ptr iść w parze. Obiekt należący do obiektu shared_ptr może być również oznaczony jako weak_ptr. Są komplementarne.

A unique_ptr ma wyłączne prawo własności do obiektu, którym zarządza; nikt inny nie może mieć własności obiektu. Jest to przeciwieństwo semantyki własności shared_ptr: z unique_ptr masz unikatowe unikatowe prawo własności; z numerem shared_ptr masz wspólne, nieunikalne prawo własności.

Możesz skonstruować shared_ptr z unique_ptr; kiedy to zrobisz, unique_ptr straci własność obiektu. Działa to, ponieważ zawsze wiesz, że dany unique_ptr jest zawsze jedynym właścicielem obiektu, więc jest w stanie zwolnić to prawo własności.

Gdy obiekt jest własnością shared_ptr, nie można zwolnić prawa własności do obiektu, ponieważ nie ma gwarancji, że dany shared_ptr jest jedynym właścicielem obiektu.

+0

@sonicoder: 'unikalne_ptr' jest niekodowane, tak jak' scoped_ptr' jest nieoprawione. Semantyka 'unique_ptr' i' scoped_ptr' nie jest oczywiście identyczna, ponieważ 'unique_ptr' może zostać przeniesiony, ale są one podobne i jest bardzo mało przypadków, w których używałbyś' scoped_ptr', ale 'unique_ptr' byłoby niepożądane. –

2
  1. scoped_ptr AFAIK nie jest częścią TR1 (Popraw mnie, jeśli się mylę). Ogólnie boost 's scoped_ptr nie może w ogóle przenieść własności. Po przypisaniu do niego wskaźnika nie można go zwolnić.
  2. unique_ptr może przenosić własność tylko za pomocą std::move, więc nie przenosi również prawa własności.
  3. shared_ptr nie może zwolnić właściciela, ponieważ mogą go udostępnić inne wskaźniki. Można go przekonwertować na weak_ptr. Jeśli spróbujesz przekonwertować go z weak_ptr, a obiekt został zwolniony, zostanie rzucony.
  4. weak_ptr może zostać utworzony z shared_ptr, po przekonwertowaniu na shared_ptr może zostać rzucony, jeśli obiekt już nie istnieje.
3

Biorąc pod uwagę dwie klasy A i B (które mogą być inteligentne typy wskaźnika), istnieją cztery główne sposoby konwertowania instancję typu B aby wpisać A:

  • A jest dostępna baza obiekt klasy B (np. B jest publicznie wyprowadzany z A), a konwersja może wyciąć lub po prostu dostosować typ odniesienia lub wskaźnika. (celowe przekreślenie).

  • A ma dostępny konstruktor pobierający B.

  • B ma dostępny operator konwersji, który generuje numer A.

  • Istnieje pewna funkcja, która pobiera B i generuje A i wywołujesz tę funkcję.

Do dziedziczenia inteligentnych wskaźników nie stosuje się do ułatwienia konwersji, ponieważ dziedziczenie pozwala na nieprawidłowe konwersje; stąd uderzenie wyżej. Na przykład, jeśli SmartPtr<Derived> odziedziczony publicznie z SmartPtr<Base>, wtedy można byłoby zrobić SmartPtr<Base>& spBase = spDerived;, a następnie np. spBase = spOtherDerived, który byłby raczej problematyczny ... Na odpowiednio wysokim poziomie abstrakcji jest to zasadniczo ten sam problem, co dla const dla konwersji wskaźnika; zobacz element FAQ: 18.17 "Why am I getting an error converting a Foo** → Foo const**?".

Tak więc, inteligentne konwersje wskaźnika są generalnie wyrażane za pomocą ostatnich trzech punktów, a mianowicie konstruktorów, operatorów konwersji i nazwanych funkcji konwersji.

Zasadniczo istnieją trzy inteligentne wskaźniki w C++ 0x, nie zważając na nieaktualnych auto_ptr:

  • std::unique_ptr dla pojedynczych obiektów.

  • std::unique_ptr dla tablic.

  • std::shared_ptr dla pojedynczych obiektów.

unique_ptr wyraża przeniesienie własności, jak stary auto_ptr zrobił i robi. Ale auto_ptr nie obsługuje tablic. unique_ptr ma, i to wpływa na możliwe konwersje.

W przypadku pojedynczych obiektów, unique_ptr obsługuje konwersje, które wykonuje odpowiednie wskaźniki surowe, za pośrednictwem konstruktorów. Ma szablonowego konstruktora pobierającego unique_ptr innego typu. Zobacz np. Projekt C++ 0x N3126 §20.9.10.2.

Ale dla tablic, które byłyby tak samo niebezpieczne, jak w przypadku surowych wskaźników! I tak dla tablic unique_ptr ma nie oferują podstawową/pochodną konwersji. Zobacz np. Projekt C++ 0x N3126 §20.9.10.3.

Od unique_ptr wyraża przeniesienie własności podczas shared_ptr wyrażona współwłasność nie może być bezpieczny ogólny konwersja z shared_ptr do unique_ptr. Jednak w inny sposób, Boost shared_ptr ma konstruktora biorąc auto_ptr, a C++ 0x shared_ptr zachowuje to (również ma) i oczywiście dodaje konstruktora biorąc unique_ptr. Patrz szkic C++ 0x N3126 §20.9.11.2/1.

shared_ptr dostarcza konwersji bazowych/pochodnych za pośrednictwem konstruktorów i za pomocą darmowych funkcji, które koncepcyjnie realizują "rzutowania". Zasadniczo oznacza to, że shared_ptr jest dość niebezpieczny do użycia bezpośrednio dla tablic obiektów typu klasy. W tym celu zapakuj go.

Konwersja z shared_ptr na unique_ptr jest, jak wspomniano, nie jest obsługiwana jako operacja ogólna. Ponieważ własność dzielona nie jest bezpośrednio zgodna z przeniesieniem własności. Pomijając jednak komplikacje. wątku bezpieczeństwa, shared_ptr::unique mówi, czy istnieje jeden właściciel (a mianowicie Twoje wystąpienie), a następnie, jeśli masz wymaganą wiedzę o tym, jak zbudowany został pierwotny shared_ptr, możesz użyć funkcji bezpłatnej get_deleter, aby uzyskać wskaźnik do funkcja deletera, i wykonaj niektóre szantanowania niskiego poziomu. Jeśli rozumiesz całkowicie, o czym tu mówię, to dobrze, dobrze. Jeśli nie, to najlepiej, że nie podaję więcej szczegółów, ponieważ jest to bardzo szczególny przypadek i wymaga najwyższej staranności oraz, że naprawdę wiesz, co robisz, ™. ;-)

Cóż, o to chodzi. Nie dyskutuję o weak_ptr, ponieważ jest to tylko część funkcji shared_ptr. Ale mam nadzieję, że powyższe jest o to pytasz.

Powiązane problemy