Czy C ++ 11 unique_ptr i shared_ptr mogą konwertować na inne typy?

105

Czy biblioteka standardowa C ++ 11 zapewnia narzędzie do konwersji z formatu a std::shared_ptrna std::unique_ptrlub odwrotnie? Czy to bezpieczna operacja?

Hind Forsum
źródło
Zdefiniuj proszę „bezpieczną obsługę”. Jakiego rodzaju bezpieczeństwa szukasz? bezpieczeństwo zarządzania na całe życie? Bezpieczeństwo wątku?
jaggedSpire
2
„STL” nie oznacza standardowej biblioteki. STL nie ma z tym nic wspólnego shared_ptr.
curiousguy
1
@jaggedSpire Bezpieczeństwo wątków oznaczałoby, że masz właścicieli używanych w różnych wątkach, tj. liczba użyć nie wynosi 1.
ciekawyGrudzień
@curiousguy Wiedziałem o tym. Chodziło mi o to, że „bezpieczeństwo” nie zostało dobrze zdefiniowane w pytaniu OP, a on musiał wyjaśnić, jakiego rodzaju „bezpieczeństwo” miał na myśli, ponieważ istnieje wiele rodzajów.
jaggedSpire

Odpowiedzi:

171

std::unique_ptr jest sposobem C ++ 11 na wyrażenie wyłącznej własności, ale jedną z jego najbardziej atrakcyjnych cech jest to, że łatwo i wydajnie konwertuje się na std::shared_ptr .

Jest to kluczowa część tego, dlaczego std::unique_ptrjest tak dobrze dopasowana jako typ zwracanej funkcji fabrycznej. Funkcje fabryczne nie mogą wiedzieć, czy wywołujący będą chcieli użyć semantyki wyłącznej własności dla obiektu, który zwracają, czy też współdzielona własność (tj. std::shared_ptr) Byłaby bardziej odpowiednia. Zwracając a std::unique_ptr, fabryki zapewniają dzwoniącym najbardziej wydajny inteligentny wskaźnik, ale nie utrudniają dzwoniącym zastąpienia go bardziej elastycznym rodzeństwem.

std::shared_ptraby std::unique_ptrnie jest dozwolone. Gdy zmienisz zarządzanie zasobami przez całe życie na a std::shared_ptr, nie możesz zmienić zdania. Nawet jeśli liczba odwołań wynosi jeden, nie możesz odzyskać prawa własności do zasobu, aby, powiedzmy, mieć plikstd::unique_ptr Zarządzać nim.

Odniesienie: Efektywne nowoczesne C ++. 42 SZCZEGÓLNE SPOSOBY POPRAWY KORZYSTANIA Z C ++ 11 I C ++ 14. Scott Meyers.

Krótko mówiąc, możesz łatwo i efektywnie przekonwertować std::unique_ptrna, std::shared_ptrale nie możesz przekonwertować std::shared_ptrna std::unique_ptr.

Na przykład:

std::unique_ptr<std::string> unique = std::make_unique<std::string>("test");
std::shared_ptr<std::string> shared = std::move(unique);

lub:

std::shared_ptr<std::string> shared = std::make_unique<std::string>("test");
chema989
źródło
9
...Jak ty to robisz?
Jake
4
@Jake Dodałem przykład
chema989
Pamiętaj, że chociaż nie jest to dozwolone, kompilator (przynajmniej nie gcc) w rzeczywistości nie zapobiegnie (ani nawet nie ostrzeże), jeśli przypadkowo (np. Zmieniając typ wskaźnika zmiennej składowej) przypiszesz a std::unique_ptrdo a std::shared_ptr.
StefanQ
@StefanQ Dlaczego myślisz, że nie można przypisać a std::unique_ptrdo a std::shared_ptr? Biblioteka standardowa definiuje operator przypisania przenoszenia template<class Y, class Deleter> shared_ptr& operator=(std::unique_ptr<Y, Deleter>&& r); dla std::shared_ptr<T>.
cuddlebugCuller
-8

Biorąc pod uwagę unique_ptr u_ptr, utwórz shared_ptr s_ptr:

std::shared_ptr<whatever> s_ptr(u_ptr.release());

Odwrotna droga jest niepraktyczna.

nmr
źródło
29
Oto „właściwy” sposób:std::shared_ptr<whatever> s_ptr(std::move(u_ptr));
emlai
6
A oto pedantyczny „właściwy” sposób:std::shared_ptr<whatever> s_ptr{std::move(u_ptr)};
polyvertex
3
Co jest w tym mniej bezpieczne?
NMR,
7
@VioletGiraffe • Przypuszczam, że firma polyvertex zaleca używanie nowej składni listy inicjalizacyjnej - która pozwala uniknąć cichych zawężających konwersji i umożliwia inicjalizację elementu członkowskiego za pomocą jednolitej składni - jako dobry nawyk. Sześć z jednego, pół tuzina drugiego?
Eljay,
9
@nmr To niebezpieczne, ponieważ możesz stracić Deleterprzechowywane wunique_ptr
Zang MingJie