วิธีการประกาศ std :: unique_ptr และการใช้งานคืออะไร?


95

ฉันพยายามที่จะเข้าใจวิธีstd::unique_ptrการทำงานและการที่ผมพบนี้เอกสาร ผู้เขียนเริ่มจากตัวอย่างต่อไปนี้:

#include <utility>  //declarations of unique_ptr
using std::unique_ptr;
// default construction
unique_ptr<int> up; //creates an empty object
// initialize with an argument
unique_ptr<int> uptr (new int(3));
double *pd= new double;
unique_ptr<double> uptr2 (pd);
// overloaded * and ->
*uptr2 = 23.5;
unique_ptr<std::string> ups (new std::string("hello"));
int len=ups->size();

สิ่งที่ทำให้ฉันสับสนคือในบรรทัดนี้

unique_ptr<int> uptr (new int(3));

เราใช้จำนวนเต็มเป็นอาร์กิวเมนต์ (ระหว่างวงเล็บกลม) และที่นี่

unique_ptr<double> uptr2 (pd);

เราใช้ตัวชี้เป็นอาร์กิวเมนต์ มันสร้างความแตกต่างหรือไม่?

สิ่งที่ยังไม่ชัดเจนสำหรับฉันคือตัวชี้ที่ประกาศในลักษณะนี้จะแตกต่างจากตัวชี้ที่ประกาศในลักษณะ "ปกติ" อย่างไร


13
new int(3)กลับชี้ไปที่ใหม่intเช่นเดียวกับเป็นตัวชี้ไปอยู่ที่ใหม่pd double
David Schwartz

คำตอบ:


89

ตัวสร้างของunique_ptr<T>ยอมรับตัวชี้ดิบไปยังวัตถุประเภทT(ดังนั้นจึงยอมรับ aT* )

ในตัวอย่างแรก:

unique_ptr<int> uptr (new int(3));

ตัวชี้เป็นผลลัพธ์ของnewนิพจน์ในขณะที่อยู่ในตัวอย่างที่สอง:

unique_ptr<double> uptr2 (pd);

ตัวชี้จะถูกเก็บไว้ในไฟล์ pdตัวแปร

ตามแนวคิดแล้วไม่มีอะไรเปลี่ยนแปลง (คุณกำลังสร้างunique_ptrตัวชี้ดิบ) แต่แนวทางที่สองอาจเป็นอันตรายมากกว่าเนื่องจากจะทำให้คุณสามารถทำสิ่งต่อไปนี้ได้

unique_ptr<double> uptr2 (pd);
// ...
unique_ptr<double> uptr3 (pd);

ดังนั้นจึงมีพอยน์เตอร์ที่ไม่ซ้ำกันสองตัวที่ห่อหุ้มวัตถุเดียวกันได้อย่างมีประสิทธิภาพ (ซึ่งเป็นการละเมิดความหมายของตัวชี้ที่ไม่ซ้ำกัน )

นี่คือเหตุผลที่รูปแบบแรกในการสร้างตัวชี้ที่ไม่ซ้ำกันจึงดีกว่าเมื่อเป็นไปได้ สังเกตว่าใน C ++ 14 เราจะสามารถทำ:

unique_ptr<int> p = make_unique<int>(42);

ซึ่งทั้งชัดเจนและปลอดภัยกว่า. ตอนนี้เกี่ยวกับข้อสงสัยของคุณ:

สิ่งที่ยังไม่ชัดเจนสำหรับฉันคือตัวชี้ที่ประกาศในลักษณะนี้จะแตกต่างจากตัวชี้ที่ประกาศในลักษณะ "ปกติ" อย่างไร

ตัวชี้สมาร์ทควรจะจำลองความเป็นเจ้าของวัตถุและดูแลการทำลายวัตถุปลายแหลมโดยอัตโนมัติเมื่อตัวชี้สุดท้าย (ฉลาดเป็นเจ้าของ) ไปยังวัตถุนั้นหลุดออกจากขอบเขต

ด้วยวิธีนี้คุณไม่ต้องจำไว้ว่าทำdeleteกับวัตถุที่จัดสรรแบบไดนามิก - ตัวทำลายของตัวชี้อัจฉริยะจะทำสิ่งนั้นให้คุณ - และไม่ต้องกังวลว่าคุณจะไม่ลดทอนตัวชี้ (ห้อย) ไปยังวัตถุที่ถูกทำลายไปแล้วหรือไม่:

{
    unique_ptr<int> p = make_unique<int>(42);
    // Going out of scope...
}
// I did not leak my integer here! The destructor of unique_ptr called delete

ตอนนี้unique_ptrเป็นตัวชี้อัจฉริยะที่จำลองการเป็นเจ้าของที่ไม่ซ้ำกันซึ่งหมายความว่าเมื่อใดก็ตามในโปรแกรมของคุณจะมีตัวชี้เพียงตัวเดียว (เป็นเจ้าของ) ไปยังวัตถุปลายแหลมนั่นคือเหตุผลว่าทำไมunique_ptrไม่ copyable

ตราบใดที่คุณใช้สมาร์ทพอยน์เตอร์ในลักษณะที่ไม่ผิดสัญญาโดยปริยายที่กำหนดให้คุณต้องปฏิบัติตามคุณจะรับประกันได้ว่าจะไม่มีการรั่วไหลของหน่วยความจำและนโยบายความเป็นเจ้าของที่เหมาะสมสำหรับวัตถุของคุณจะถูกบังคับใช้ ตัวชี้ดิบไม่ให้การรับประกันนี้แก่คุณ


3
สวัสดีครับผมไม่เข้าใจอะไรเกี่ยวกับmodel object ownershipที่อยู่ในรหัสหรือinteger leak enforcing ownership policy for objectคุณช่วยแนะนำหัวข้อ / แหล่งข้อมูลเพื่อเรียนรู้แนวคิดเหล่านี้ได้ไหม
Flame of udun

1
ฉันไม่สามารถใช้งานunique_ptrได้โดยไม่ได้รับข้อผิดพลาด: The text ">" is unexpected. It may be that this token was intended as a template argument list terminator but the name is not known to be a template.แม้ว่าฉันจะมี#include <utility>และ#include <memory>. คำแนะนำใด ๆ?
ไม่ระบุชื่อ

15

ไม่มีความแตกต่างในการทำงานทั้งในแนวคิดของการมอบหมายให้ unique_ptr

int* intPtr = new int(3);
unique_ptr<int> uptr (intPtr);

เหมือนกับ

unique_ptr<int> uptr (new int(3));

ที่นี่unique_ptrจะลบพื้นที่ที่ครอบครองโดยuptrอัตโนมัติ


พอยน์เตอร์ที่ประกาศในลักษณะนี้จะแตกต่างจากพอยน์เตอร์ที่ประกาศในลักษณะ "ปกติ" อย่างไร

หากคุณสร้างจำนวนเต็มในฮีปสเปซ (โดยใช้คีย์เวิร์ดใหม่หรือmalloc ) คุณจะต้องล้างหน่วยความจำนั้นด้วยตัวคุณเอง (โดยใช้ลบหรือว่างตามลำดับ)

ในโค้ดด้านล่างนี้

int* heapInt = new int(5);//initialize int in heap memory
.
.//use heapInt
.
delete heapInt;

ที่นี่คุณจะต้องลบ heapInt เมื่อเสร็จแล้วโดยใช้ หากไม่ได้ลบออกแสดงว่าเกิดการรั่วไหลของหน่วยความจำ

เพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำดังกล่าวunique_ptrถูกนำมาใช้ที่ unique_ptr โดยอัตโนมัติลบพื้นที่ที่ถูกครอบครองโดย heapInt เมื่อมันไปจากขอบเขต ดังนั้นคุณไม่จำเป็นต้องลบหรือฟรีสำหรับ unique_ptr


10

พอยน์เตอร์เฉพาะรับประกันว่าจะทำลายวัตถุที่จัดการเมื่ออยู่นอกขอบเขต http://en.cppreference.com/w/cpp/memory/unique_ptr

ในกรณีนี้:

unique_ptr<double> uptr2 (pd);

pd จะถูกทำลายเมื่อ uptr2อยู่นอกขอบเขต สิ่งนี้ช่วยอำนวยความสะดวกในการจัดการหน่วยความจำโดยการลบอัตโนมัติ

กรณีของunique_ptr<int> uptr (new int(3));ไม่แตกต่างกันยกเว้นว่าตัวชี้ดิบไม่ได้กำหนดให้กับตัวแปรใด ๆ ที่นี่


-1

จากcppreferenceหนึ่งในตัวstd::unique_ptrสร้างคือ

unique_ptr อย่างชัดเจน (ตัวชี้ p) noexcept;

ดังนั้นการสร้างใหม่std::unique_ptrคือการส่งตัวชี้ไปยังตัวสร้าง

unique_ptr<int> uptr (new int(3));

หรือจะเหมือนกับ

int *int_ptr = new int(3);
std::unique_ptr<int> uptr (int_ptr);

สิ่งที่แตกต่างคือคุณไม่ต้องทำความสะอาดหลังจากใช้งาน ถ้าคุณไม่ใช้std::unique_ptr(ตัวชี้อัจฉริยะ) คุณจะต้องลบออกเช่นนี้

delete int_ptr;

เมื่อคุณไม่ต้องการอีกต่อไปมิฉะนั้นจะทำให้หน่วยความจำรั่วไหล

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