Metode pop daftar tertaut menggunakan unique_ptr

Aug 20 2020

Saya melihat penerapan daftar tertaut tunggal menggunakan unique_ptrdihttps://solarianprogrammer.com/2019/02/22/cpp-17-implementing-singly-linked-list-smart-pointers/. Pertanyaan saya berkaitan dengan metode berikut:

 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 };

Saya bertanya-tanya mengapa sementara diperlukan di sini? Mengapa Anda tidak bisa begitu saja melakukannya head = std::move(head->next)? Apakah ini karena akan mengakibatkan kebocoran memori? Saat headditetapkan ulang, apakah unique_ptrsecara otomatis membebaskan memori yang saat ini ditunjuk?

Saya mendapat kesan bahwa petunjuk pintar adalah bukti bodoh dari kebocoran memori. Tampaknya dalam kasus ini mungkin ada kebocoran memori untuk aslinya headkarena tidak akan ada lagi penunjuk cerdas yang menunjuk ke sana?

Jawaban

4 RemyLebeau Aug 20 2020 at 07:36

Saya bertanya-tanya mengapa sementara diperlukan di sini?

Ini tidak terlalu dibutuhkan , tapi tidak buruk juga untuk digunakan.

Mengapa Anda tidak bisa begitu saja melakukannya head = std::move(head->next)? Apakah ini karena akan mengakibatkan kebocoran memori?

Kamu bisa. Tidak akan ada kebocoran dalam contoh ini.

Saat headditetapkan ulang, apakah unique_ptrsecara otomatis membebaskan memori yang saat ini ditunjuk?

Iya. Namun, penunjuk lama tidak akan digunakan deletesampai kepemilikan penunjuk baru ditransfer terlebih dahulu. Per cppreference:

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

Mentransfer kepemilikan dari rke *thisseolah-olah dengan menelepon reset(r.release())diikuti dengan penugasan get_deleter()dari std::forward<E>(r.get_deleter()).

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

Mengganti objek yang dikelola.

  1. Diberikan current_ptr, penunjuk yang dikelola oleh *this, melakukan tindakan berikut, dalam urutan ini:

    1. Menyimpan salinan penunjuk saat ini old_ptr = current_ptr
    2. Menimpa penunjuk saat ini dengan argumen current_ptr = ptr
    3. Jika penunjuk lama tidak kosong, menghapus objek yang dikelola sebelumnya
      if(old_ptr) get_deleter()(old_ptr).

Begitu:

Dalam kasus di mana tempdigunakan, penunjuk ke node lama di headpertama-tama akan dipindahkan ke tempmelalui konstruktor pemindahnya, mengatur ulang headuntuk menahan a nullptr. Kemudian head.operator=akan memanggil next.release()dan mendapatkan penunjuk itu. Dan kemudian tempakan keluar dari ruang lingkup, deletedengan node lama.

Dalam kasus di mana temptidak digunakan, head.operator=akan memanggil next.release(), menyimpan penunjuk lamanya dan menggantinya dengan penunjuk yang dilepaskan, dan kemudian deletepenunjuk yang disimpan.

Tidak ada kebocoran.

Saya mendapat kesan bahwa petunjuk pintar adalah bukti bodoh dari kebocoran memori.

Jika digunakan dengan benar , ya.

Tampaknya dalam kasus ini mungkin ada kebocoran memori untuk aslinya headkarena tidak akan ada lagi penunjuk cerdas yang menunjuk ke sana?

Tidak ada kebocoran, karena selalu ada yang unique_ptrmerujuk ke node lama, sampai pop()keluar dan tempdihancurkan, deletedengan node lama bersamanya. Bahkan jika tempdihilangkan, node lama masih dihancurkan dengan benar setelah kepemilikan nextpointernya ditransfer.