วิธีป๊อปของรายการที่เชื่อมโยงโดยใช้ unique_ptr

Aug 20 2020

ฉันกำลังดูการใช้งานรายการที่เชื่อมโยงเดี่ยวโดยใช้unique_ptronhttps://solarianprogrammer.com/2019/02/22/cpp-17-implementing-singly-linked-list-smart-pointers/. คำถามของฉันเกี่ยวข้องกับวิธีการต่อไปนี้:

 3 struct List {
 4     List() : head{nullptr} {};
 5 
 6     // ...
 7 
 8     void pop() {
 9         if(head == nullptr) {
10             return;
11         }
12 
13         std::unique_ptr<Node> temp = std::move(head);
14         head = std::move(temp->next);
15     }
16 
17     // ...
18 };

ฉันสงสัยว่าทำไมต้องใช้ชั่วคราวที่นี่? ทำไมคุณทำhead = std::move(head->next)ไม่ได้? เป็นเพราะมันจะส่งผลให้หน่วยความจำรั่วหรือเปล่า? เมื่อheadถูกกำหนดใหม่จะunique_ptrทำให้หน่วยความจำปัจจุบันถูกชี้ไปโดยอัตโนมัติหรือไม่?

ฉันรู้สึกว่าตัวชี้อัจฉริยะเป็นหลักฐานที่โง่เขลาจากการรั่วไหลของหน่วยความจำ ดูเหมือนว่าในกรณีนี้อาจมีการรั่วไหลของหน่วยความจำสำหรับต้นฉบับheadเนื่องจากจะไม่มีตัวชี้อัจฉริยะชี้ไปที่มันอีกต่อไป?

คำตอบ

4 RemyLebeau Aug 20 2020 at 07:36

ฉันสงสัยว่าทำไมต้องใช้ชั่วคราวที่นี่?

มันไม่จำเป็นจริงๆแต่ก็ไม่เลวที่จะใช้เช่นกัน

ทำไมคุณทำhead = std::move(head->next)ไม่ได้? เป็นเพราะมันจะส่งผลให้หน่วยความจำรั่วหรือเปล่า?

คุณสามารถ. จะไม่มีการรั่วไหลในตัวอย่างนี้

เมื่อheadถูกกำหนดใหม่จะunique_ptrทำให้หน่วยความจำปัจจุบันถูกชี้ไปโดยอัตโนมัติหรือไม่?

ใช่. อย่างไรก็ตามตัวชี้เก่าจะไม่ถูกdelete'd จนกว่าจะโอนความเป็นเจ้าของตัวชี้ใหม่ก่อน ต่อ cppreference:

https://en.cppreference.com/w/cpp/memory/unique_ptr/operator%3D

เจ้าของรับส่งจากrไป*thisราวกับว่าโดยการเรียกreset(r.release())ตามที่ได้รับมอบหมายของจากget_deleter()std::forward<E>(r.get_deleter())

https://en.cppreference.com/w/cpp/memory/unique_ptr/reset

แทนที่วัตถุที่มีการจัดการ

  1. ระบุcurrent_ptrตัวชี้ที่ถูกจัดการโดย*thisดำเนินการต่อไปนี้ตามลำดับนี้:

    1. บันทึกสำเนาของตัวชี้ปัจจุบัน old_ptr = current_ptr
    2. เขียนทับตัวชี้ปัจจุบันด้วยอาร์กิวเมนต์ current_ptr = ptr

    3. if(old_ptr) get_deleter()(old_ptr)หากตัวชี้เก่าไม่ว่างเปล่าลบวัตถุที่มีการจัดการก่อนหน้านี้

ดังนั้น:

ในกรณีที่tempมีการใช้งานตัวชี้ไปยังโหนดเก่าในheadจะถูกย้ายไปที่tempตัวสร้างการย้ายก่อนโดยการรีเซ็ตheadเพื่อถือ a nullptr. จากนั้นhead.operator=จะเรียกnext.release()และรับตัวชี้นั้น จากนั้นtempจะออกนอกขอบเขตdelete'ในโหนดเก่า

ในกรณีที่tempไม่ได้ใช้งานhead.operator=จะโทรnext.release()บันทึกตัวชี้เก่าและแทนที่ด้วยตัวชี้ที่ปล่อยแล้วจากนั้นdeleteตัวชี้ที่บันทึกไว้

ไม่มีการรั่วไหลทั้งสองทาง

ฉันรู้สึกว่าตัวชี้อัจฉริยะเป็นหลักฐานที่โง่เขลาจากการรั่วไหลของหน่วยความจำ

ถ้าใช้ถูกก็ใช่

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

ไม่มีการรั่วไหลเนื่องจากมีการunique_ptrอ้างถึงโหนดเก่าอยู่เสมอจนกว่าจะpop()ออกและtempถูกทำลายdelete'ติดตั้งโหนดเก่าด้วย แม้ว่าtempจะถูกละไว้โหนดเก่าก็ยังคงถูกทำลายอย่างเหมาะสมหลังจากโอนความเป็นเจ้าของnextตัวชี้แล้ว