Temui Pointer Detektor Sampah Deterministik

Memori, dalam C ++ selalu sulit untuk bekerja dengannya (warisan pahit dari C ) ... Di sini C ++ 11 dengan std :: shared_ptr datang ke bantuan kami.


Seperti yang mungkin sudah Anda duga, jika primitif ini tidak memiliki masalah, maka artikel ini tidak akan :)

Mari kita lihat contoh kebocoran memori klasik berikut di std :: shared_ptr :

#include <iostream> #include <memory> class Child; class Parent { public: Parent() { std::cout << "Parent()" << std::endl; } ~Parent() { std::cout << "~Parent()" << std::endl; } void createChild() { child_ptr_ = std::make_shared<Child>(); } std::shared_ptr<Child> getChild() { return child_ptr_; } private: std::shared_ptr<Child> child_ptr_; }; class Child { public: Child() { std::cout << "Child()" << std::endl; } ~Child() { std::cout << "~Child()" << std::endl; } void setParent(std::shared_ptr<Parent> parentPtr) { parent_ptr_ = parentPtr; } private: std::shared_ptr<Parent> parent_ptr_; }; int main() { auto parent = std::make_shared<Parent>(); parent->createChild(); parent->getChild()->setParent(parent); return 0; } 

Jelas, kita tidak akan melihat panggilan penghancur objek. Bagaimana cara mengatasinya? std :: lemah_ptr datang ke bantuan kami:

 ... class Child { ... void setParent(std::shared_ptr<Parent> parentPtr) { parent_ptr_ = parentPtr; } private: std::weak_ptr<Parent> parent_ptr_; }; ... 

Ya, ini membantu menyelesaikan masalah. Tetapi jika Anda memiliki hierarki objek yang lebih kompleks dan sangat sulit untuk memahami siapa yang harus melakukan std :: lemah_ptr dan siapa yang harus std :: shared_ptr ? Atau apakah Anda tidak ingin dipusingkan dengan koneksi yang longgar sama sekali?

Pengumpul Sampah adalah segalanya bagi kami !!

Tidak, tentu saja tidak. Di C ++, tidak ada dukungan asli untuk Pengumpul Sampah, dan bahkan jika ditambahkan, kami mendapatkan biaya overhead untuk Pengumpul Sampah, ditambah istirahat RAII.

Apa yang kita lakukan

Deterministic Garbage Collector Pointer adalah Pointer yang melacak semua tautan dari objek root dan segera setelah tidak ada objek root yang merujuk ke objek kami, ia langsung dihapus.

Prinsip operasinya mirip dengan std :: shared_ptr (ini melacak lingkup ), tetapi juga objek yang mereferensikannya.

Mari kita lihat prinsip operasinya pada contoh sebelumnya:

 #include <iostream> #include "gc_ptr.hpp" class Child; class Parent { public: Parent() { std::cout << "Parent()" << std::endl; } ~Parent() { std::cout << "~Parent()" << std::endl; } void createChild() { child_ptr_.create_object(); } memory::gc_ptr<Child> getChild() { return child_ptr_; } void connectToRoot(void * rootPtr) { child_ptr_.connectToRoot(rootPtr); } void disconnectFromRoot(bool isRoot, void * rootPtr) { child_ptr_.disconnectFromRoot(isRoot, rootPtr); } private: memory::gc_ptr<Child> child_ptr_; }; class Child { public: Child() { std::cout << "Child()" << std::endl; } ~Child() { std::cout << "~Child()" << std::endl; } void setParent(memory::gc_ptr<Parent> parentPtr) { parent_ptr_ = parentPtr; } void connectToRoot(void * rootPtr) { parent_ptr_.connectToRoot(rootPtr); } void disconnectFromRoot(bool isRoot, void * rootPtr) { parent_ptr_.disconnectFromRoot(isRoot, rootPtr); } private: memory::gc_ptr<Parent> parent_ptr_; }; int main() { memory::gc_ptr<Parent> parent; parent.create_object(); parent->createChild(); parent->getChild()->setParent(parent); return 0; } 

Seperti yang Anda lihat, kode telah menjadi sedikit lebih, tetapi ini adalah harga yang harus Anda bayar untuk penghapusan objek secara otomatis. Dapat dilihat bahwa metode connectToRoot tambahan dan disconnectFromRoot telah ditambahkan. Tentu saja, menulis dengan tangan mereka sepanjang waktu akan sangat sulit, jadi saya bermaksud membuat generator kecil dari metode ini di kelas yang menggunakan gc_ptr (seperti yang kita lihat kita mematuhi prinsip Zero-Overhead , kita tidak membayar untuk apa yang tidak kita gunakan, dan jika kita menggunakan- maka biayanya tidak lebih dari jika kita menulisnya dengan tangan kita).

Pustaka gc_ptr.hpp adalah thread-safe, tidak membuat utas tambahan untuk pengumpulan sampah, semuanya dilakukan di konstruktor, destructor dan operator penugasan, jadi jika kita menimpa objek kita dan tidak ada objek root yang merujuknya lagi, maka kita kembali memori yang dialokasikan untuk objek kita.

Terima kasih atas perhatian anda!

Source: https://habr.com/ru/post/id462583/


All Articles