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!