C ++ 11 unique_ptr และ shared_ptr สามารถแปลงเป็นประเภทของกันและกันได้หรือไม่?


108

ไม่ C ++ 11 ห้องสมุดมาตรฐานให้ยูทิลิตี้ใด ๆ ที่จะแปลงจากstd::shared_ptrไปstd::unique_ptrหรือกลับกัน? การดำเนินการนี้ปลอดภัยหรือไม่?


โปรดระบุ "การทำงานที่ปลอดภัย" คุณกำลังมองหาความปลอดภัยประเภทใด ความปลอดภัยในการจัดการอายุการใช้งาน? ความปลอดภัยของด้าย?
jaggedSpire

2
"STL" ไม่ได้หมายถึงไลบรารีมาตรฐาน STL shared_ptrมีอะไรจะทำอย่างไรกับ
ซอกแซก

1
@jaggedSpire ความปลอดภัยของกระทู้จะหมายความว่าคุณมีเจ้าของที่ใช้ในหัวข้อที่แตกต่างกันเช่นการนับจำนวนการใช้งานที่ไม่ได้เป็น 1.
curiousguy

@curiousguy ฉันรู้ว่า ประเด็นของฉันคือ "ความปลอดภัย" ไม่ได้กำหนดไว้อย่างชัดเจนในคำถามของ OP และเขาจำเป็นต้องชี้แจงว่า "ความปลอดภัย" ประเภทใดที่เขาหมายถึงเนื่องจากมีหลายประเภท
jaggedSpire

คำตอบ:


174

std::unique_ptrเป็นวิธี C ++ 11 ในการแสดงความเป็นเจ้าของ แต่เพียงผู้เดียว แต่คุณสมบัติที่น่าสนใจที่สุดประการหนึ่งคือการแปลงเป็นไฟล์std::shared_ptr.

นี่เป็นส่วนสำคัญว่าเหตุใดstd::unique_ptrจึงเหมาะอย่างยิ่งกับประเภทการส่งคืนฟังก์ชันจากโรงงาน ฟังก์ชั่นโรงงานไม่สามารถทราบได้ว่าผู้โทรจะต้องการใช้ความหมายความเป็นเจ้าของเฉพาะตัวสำหรับออบเจ็กต์ที่พวกเขาส่งคืนหรือไม่ว่าการเป็นเจ้าของร่วมกัน (กล่าวคือstd::shared_ptr) จะเหมาะสมกว่าหรือไม่ ด้วยการส่งคืน a std::unique_ptrโรงงานจะจัดหาตัวชี้อัจฉริยะที่มีประสิทธิภาพสูงสุดให้กับผู้โทร แต่ก็ไม่ขัดขวางผู้โทรจากการแทนที่ด้วยพี่น้องที่ยืดหยุ่นกว่า

std::shared_ptrจะstd::unique_ptrไม่ได้รับอนุญาต เมื่อคุณเปลี่ยนการจัดการทรัพยากรตลอดชีวิตไปเป็น a std::shared_ptrแล้วคุณจะไม่เปลี่ยนใจ แม้ว่าจำนวนการอ้างอิงจะเป็นหนึ่ง แต่คุณไม่สามารถอ้างสิทธิ์ความเป็นเจ้าของทรัพยากรเพื่อที่จะกล่าวว่ามีการstd::unique_ptrจัดการ

อ้างอิง: C ++ สมัยใหม่ที่มีประสิทธิภาพ 42 วิธีเฉพาะในการปรับปรุงการใช้ C ++ 11 และ C ++ 14 ของคุณ Scott Meyers

ในระยะสั้นที่คุณสามารถได้อย่างง่ายดายและมีประสิทธิภาพแปลงstd::unique_ptrไปstd::shared_ptrแต่คุณไม่สามารถแปลงไปstd::shared_ptrstd::unique_ptr

ตัวอย่างเช่น:

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

หรือ:

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

10
...คุณจะทำอย่างไรมันได้หรือไม่?
Jake

4
@Jake ฉันได้เพิ่มตัวอย่าง
chema989

โปรดทราบว่าในขณะที่ไม่อนุญาตคอมไพเลอร์ (อย่างน้อยก็ไม่ใช่ gcc) จริง ๆ แล้วจะไม่ป้องกัน (หรือแม้แต่เตือน) หากคุณบังเอิญ (เช่นโดยการเปลี่ยนชนิดตัวชี้ของตัวแปรสมาชิก) กำหนด a std::unique_ptrให้กับ a std::shared_ptr.
StefanQ


@StefanQ อะไรทำให้คุณคิดว่าไม่อนุญาตให้กำหนดเป็นstd::unique_ptra std::shared_ptr? ห้องสมุดมาตรฐานกำหนดผู้ประกอบการที่ได้รับมอบหมายย้าย สำหรับtemplate<class Y, class Deleter> shared_ptr& operator=(std::unique_ptr<Y, Deleter>&& r); std::shared_ptr<T>
cuddlebugCuller

-8

ให้ unique_ptr u_ptr สร้าง shared_ptr s_ptr:

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

ไปทางอื่นก็ทำไม่ได้


30
นี่คือวิธีที่ "ถูกต้อง":std::shared_ptr<whatever> s_ptr(std::move(u_ptr));
emlai

7
และนี่คือวิธีที่ "ถูกต้อง" ที่std::shared_ptr<whatever> s_ptr{std::move(u_ptr)};
อวดดี

3
อะไรที่ปลอดภัยน้อยกว่านี้?
nmr

7
@VioletGiraffe •ฉันคิดว่า polyvertex กำลังสนับสนุนการใช้ไวยากรณ์รายการเริ่มต้นใหม่ซึ่งจะหลีกเลี่ยงการแปลงที่แคบลงและรองรับการเริ่มต้นของสมาชิกด้วยไวยากรณ์ที่เหมือนกันซึ่งเป็นนิสัยที่ดีในการเข้าใช้ หกในหนึ่งครึ่งโหล?
Eljay

10
@nmr มันไม่ปลอดภัยเพราะคุณอาจสูญเสียที่Deleterเก็บไว้ในunique_ptr
Zang MingJie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.