Apakah C ++ 11 unique_ptr dan shared_ptr dapat mengonversi ke tipe satu sama lain?

101

Apakah pustaka standar C ++ 11 menyediakan utilitas apa pun untuk mengonversi dari a std::shared_ptrke std::unique_ptr, atau sebaliknya? Apakah operasi ini aman?

Hind Forsum
sumber
Tolong tentukan "operasi yang aman". Keamanan seperti apa yang Anda cari? keamanan manajemen seumur hidup? Keamanan benang?
jaggedSpire
2
"STL" tidak berarti pustaka standar. STL tidak ada hubungannya dengan shared_ptr.
penasaran
1
@jaggedSpire Keamanan utas berarti Anda memiliki pemilik yang digunakan di utas yang berbeda, yaitu jumlah penggunaan bukan 1.
penasaranGuy
@curiousguy Saya tahu itu. Maksud saya adalah "keamanan" tidak didefinisikan dengan baik dalam pertanyaan OP, dan dia perlu menjelaskan jenis "keamanan" yang dia maksud karena ada beberapa jenis.
jaggedSpire

Jawaban:

163

std::unique_ptradalah cara C ++ 11 untuk mengekspresikan kepemilikan eksklusif, tetapi salah satu fiturnya yang paling menarik adalah cara ini diubah dengan mudah dan efisien menjadi file std::shared_ptr.

Ini adalah bagian penting mengapa std::unique_ptrsangat cocok sebagai jenis pengembalian fungsi pabrik. Fungsi pabrik tidak dapat mengetahui apakah pemanggil akan ingin menggunakan semantik kepemilikan eksklusif untuk objek yang mereka kembalikan atau apakah kepemilikan bersama (yaitu std::shared_ptr) akan lebih sesuai. Dengan mengembalikan a std::unique_ptr, pabrik menyediakan penelepon dengan penunjuk cerdas yang paling efisien, tetapi mereka tidak menghalangi penelepon untuk menggantinya dengan saudara kandungnya yang lebih fleksibel.

std::shared_ptruntuk std::unique_ptrtidak diperbolehkan. Setelah Anda mengubah manajemen seumur hidup sumber daya menjadi std::shared_ptr, tidak ada yang berubah pikiran. Meskipun jumlah referensi adalah satu, Anda tidak dapat mengklaim kembali kepemilikan sumber daya untuk, misalnya, std::unique_ptrmengelolanya.

Referensi: C ++ Modern Efektif. 42 CARA KHUSUS UNTUK MENINGKATKAN PENGGUNAAN C ++ 11 DAN C ++ 14. Scott Meyers.

Singkatnya, Anda dapat dengan mudah dan efisien mengkonversi std::unique_ptrke std::shared_ptrtetapi Anda tidak dapat mengkonversi std::shared_ptrke std::unique_ptr.

Sebagai contoh:

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

atau:

std::shared_ptr<std::string> shared = std::make_unique<std::string>("test");
chema989
sumber
9
...Bagaimana Anda melakukannya?
Jake
4
@Jake Saya telah menambahkan contoh
chema989
Sadarilah bahwa meskipun tidak diizinkan, kompilator (setidaknya bukan gcc) sebenarnya tidak akan mencegah (atau bahkan memperingatkan) jika Anda secara tidak sengaja (misalnya dengan mengubah tipe penunjuk dari variabel anggota) menetapkan a std::unique_ptrke a std::shared_ptr.
StefanQ
-8

Diberikan unique_ptr u_ptr, buat shared_ptr s_ptr:

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

Pergi ke arah lain tidak praktis.

nmr
sumber
29
Inilah cara yang "benar":std::shared_ptr<whatever> s_ptr(std::move(u_ptr));
emlai
6
Dan inilah cara "benar" yang bertele-tele:std::shared_ptr<whatever> s_ptr{std::move(u_ptr)};
polyvertex
3
Apa yang kurang aman tentang itu?
nmr
7
@VioletGiraffe • Saya kira polyvertex menganjurkan penggunaan sintaks daftar inisialisasi baru - yang menghindari konversi penyempitan diam-diam dan mengakomodasi inisialisasi anggota dengan sintaks yang seragam - sebagai kebiasaan yang baik untuk dilakukan. Enam dari satu, setengah lusin lainnya?
Eljay
8
@nmr Ini tidak aman karena Anda mungkin kehilangan Deletersimpanan di dalamunique_ptr
Zang MingJie