C++智慧指標簡單實現
阿新 • • 發佈:2019-01-24
#include <iostream> #include <string> #include <vector> #include <list> namespace smart_pointer { // RAII(Resource Acquisition Is Initialization):資源分配即初始化,是管理資源、避免記憶體洩露的方法。 // 方法是:定義一個類來封裝資源的分配和釋放,在建構函式完成資源的分配和初始化,在解構函式完成資源的的清理,可以保證資源的正確初始化和釋放。 // 參考 http://blog.csdn.net/ER_Plough/article/details/48206439?ref=myread // http://blog.csdn.net/daniel_ustc/article/details/23096229 // 迴圈引用 // 迴圈引用”簡單來說就是:兩個物件互相使用一個shared_ptr成員變數指向對方的會造成迴圈引用。 // 即A內部有指向B,B內部有指向A,這樣對於A,B必定是在A析構後B才析構,對於B,A必定是在B析構後才析構A,這就是迴圈引用問題,違反常規,導致記憶體洩露。 // 解決迴圈引用方法: // 1. 當只剩下最後一個引用的時候需要手動打破迴圈引用釋放物件。 // 2. 當A的生存期超過B的生存期的時候,B改為使用一個普通指標指向A。 // 3. 使用weak_ptr打破這種迴圈引用,因為weak_ptr不會修改計數器的大小,所以就不會產生兩個物件互相使用一個shared_ptr成員變數指向對方的問題,從而不會引起引用迴圈。 // 強引用和弱引用 // 一個強引用當被引用的物件活著的話,這個引用也存在(就是說,當至少有一個強引用,那麼這個物件就不能被釋放)。 // share_ptr就是強引用。相對而言,弱引用當引用的物件活著的時候不一定存在。僅僅是當它存在的時候的一個引用。弱引用並不修改該物件的引用計數, // 這意味這弱引用它並不對物件的記憶體進行管理,在功能上類似於普通指標,然而一個比較大的區別是,弱引用能檢測到所管理的物件是否已經被釋放,從而避免訪問非法記憶體。 // 1.AutoPtr-----管理權轉移 // 2.ScopedPtr------防拷貝 // 3.SharePtr------引用計數 //----------------------------------------------------------------------------------- // 1.AutoPtr template<class T> class AutoPtr { public: explicit AutoPtr(T* ptr); ~AutoPtr(); AutoPtr(AutoPtr<T>& auto_ptr); T* get() const { return ptr_; } void reset(T* ptr); T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } bool operator!() const { return ptr_ == NULL; } explicit operator bool() const { return ptr_ != NULL; } AutoPtr& operator=(AutoPtr<T>& auto_ptr); private: T* ptr_; }; template<class T> AutoPtr<T>::AutoPtr(T* ptr) : ptr_(ptr) { } template<class T> AutoPtr<T>::~AutoPtr() { if (ptr_ != NULL) { delete ptr_; ptr_ = NULL; } } template<class T> AutoPtr<T>::AutoPtr(AutoPtr<T>& auto_ptr) { ptr_ = auto_ptr.ptr_; auto_ptr.ptr_ = NULL; } template<class T> AutoPtr<T>& AutoPtr<T>::operator=(AutoPtr<T>& auto_ptr) { if (&auto_ptr == this) { return *this; } if (ptr_ != NULL) { delete ptr_; } ptr_ = auto_ptr.ptr_; auto_ptr.ptr_ = NULL; return *this; } template<class T> void AutoPtr<T>::reset(T* ptr) { if (ptr_ != NULL) { delete ptr_; } ptr_ = ptr; } template<class T, class D> bool operator==(const AutoPtr<T>& lhs, const AutoPtr<D>& rhs) { return lhs.get() == rhs.get(); } template<class T, class D> bool operator!=(const AutoPtr<T>& lhs, const AutoPtr<D>& rhs) { return lhs.get() != rhs.get(); } //----------------------------------------------------------------------------------- // ScopedPtr template<class T> class ScopedPtr { public: explicit ScopedPtr(T* ptr) : ptr_(ptr) { } ~ScopedPtr() { if (ptr_ != NULL) { delete ptr_; ptr_ = NULL; } } T* operator->() const { return ptr_; } private: ScopedPtr(const ScopedPtr<T>& scoped_ptr); ScopedPtr& operator=(const ScopedPtr<T>& scoped_ptr); private: T* ptr_; }; //----------------------------------------------------------------------------------- // ScopedPtr template<class T> class SharedPtr { public: explicit SharedPtr(T* ptr) : ptr_(ptr) { count_ = new int(1); } SharedPtr() : ptr_(NULL) , count_(NULL) { } ~SharedPtr() { Release(); } SharedPtr(const SharedPtr<T>& shared_ptr) : ptr_(shared_ptr.ptr_) , count_(shared_ptr.count_) { ++(*count_); } SharedPtr<T>& operator=(const SharedPtr<T>& shared_ptr) { if (&shared_ptr != this) { Release(); ptr_ = shared_ptr.ptr_; count_ = shared_ptr.count_; ++(*count_); } return *this; } T* operator->() const { return ptr_; } private: void Release() { if (ptr_ == NULL) { return; } --(*count_); if (*count_ == 0) { delete ptr_; delete count_; } } private: T* ptr_; int* count_; }; //----------------------------------------------------------------------------------- // Test class String1 { public: explicit String1(const std::string& name) : name_(name) { std::cout << "Construct String1 : " << name_ << "!" << std::endl; } ~String1() { std::cout << "Destruct String1! : " << name_ << "!" << std::endl; } void Print() { std::cout << "I am " << name_ << "!" << std::endl; } private: std::string name_; }; class B; class A { public: SharedPtr<B> b; ~A() { std::cout << "Destruct A!" << std::endl; } }; class B { public: SharedPtr<A> a; ~B() { std::cout << "Destruct B!" << std::endl; } }; static void TestAutoPtr() { AutoPtr<String1> ptr1(new String1("N1")); AutoPtr<String1> ptr2(ptr1); if (ptr1.get() == NULL) { std::cout << "true" << std::endl; } AutoPtr<String1> ptr3(new String1("N2")); ptr3 = ptr2; if (ptr2.get() == NULL) { std::cout << "true" << std::endl; } ptr3.reset(new String1("N4")); (*ptr3).Print(); ptr3->Print(); AutoPtr<int> ptr4(NULL); if (!ptr4) { std::cout << "true" << std::endl; } if (ptr3) { std::cout << "true" << std::endl; } if (ptr3 == ptr1) { std::cout << "true" << std::endl; } if (ptr3 != ptr1) { std::cout << "true" << std::endl; } } static void TestScopedPtr() { ScopedPtr<String1> ptr1(new String1("M1")); //ScopedPtr<String1> ptr2(ptr1); // error ScopedPtr<String1> ptr3(new String1("M3")); //ptr3 = ptr1; // error ptr1->Print(); } static void TestSharedPtr() { SharedPtr<String1> ptr1(new String1("Z1")); SharedPtr<String1> ptr2(new String1("Z2")); SharedPtr<String1> ptr3(ptr1); ptr2 = ptr3; ptr1->Print(); ptr2->Print(); ptr3->Print(); } static void TestCircularReference() { SharedPtr<A> a(new A); SharedPtr<B> b(new B); a->b = b; b->a = a; } static void TestDestructOrder() { String1 a("a"); String1 b("b"); } } // smart_pointer int main_smart() { using namespace smart_pointer; //TestDestructOrder(); //TestAutoPtr(); //TestScopedPtr(); //TestSharedPtr(); //TestCircularReference(); return 0; }