C++ 智能指针
智能指针本身是个类,程序员在为指针进行内存分配后,可能忘记使用delete销毁内存,为了避免这个问题,出现了智能指针。智能指针在创建时调用构造函数,在消亡时(超出使用范围以后)自动调用析构函数,这样就起到一个内存回收的作用。智能指针的对象都是栈上创建。
2、四种智能指针讲解
2.1 std::auto_ptr
std::auto_ptr属于C++98方案,C++11已经弃用。不支持复制(拷贝构造函数)和赋值(operator =),但进行该操作时编译器不会报错。该指针采用所有权模式,假设有std::auto_ptr p1和p2,此时p1已经初始化,将p1赋值给p2,则p2剥夺了p1的所有权,当程序运行时访问p1会报错,因为此时p1所指位置并不确定,因此存在潜在内存问题。
2.2 std::unique_ptr
std::unique_ptr是C++11中新增的用来替代auto_ptr的智能指针。std::unique_ptr实现独占式拥有或严格拥有概念,保证同一时间内只有一个只能指针可以指向该对象,同时智能指针本身是一个类,在对象生命周期结束以后会自动调用析构函数释放内存,从而避免了内存泄漏问题。那么刚才说的有关std::auto_ptr出现的情况如果用std::unique_ptr替换则无法通过编译,需要赋值时调用std::move方法。
2.3 std::shared_ptr
std::shared_ptr实现共享式拥有,多个智能指针可以指向一个相同对象,该对象和其相关资源会在最后一个引用被销毁时释放。std::shared_ptr是为了解决std::auto_ptr在对象所有权上的局限性,在使用引用计数的机制上提供了可以共享所有权的智能指针。
2.4 std::weak_ptr
std::weak_ptr是一中不控制对象生命周期的智能指针,属于弱引用。它指向一个std::shared_ptr管理的对象,其设计的目的是为了配合std::shared_ptr的使用,它只能从一个std::shared_ptr或另一个std::weak_ptr对象构造,其构造和析构不会引起引用计数的增加或减少。std::weak_ptr是用来解决std::shared_ptr相互引用时的死锁问题(如果两个std::shared_ptr相互引用,那么这两个指针的引用计数永远不可能降到0,资源永远不能释放)。
1 #include <atomic> 2 #include <string> 3 #include <iostream> 4 5 template <typename T> 6 static void Del(T*& p) 7 { 8 if (p != nullptr) 9 { 10 delete p; 11 } 12 p = nullptr; 13 } 14 15 template <typename T> 16 class CSharedPtr 17 { 18 public: 19 CSharedPtr(T* ptr) : m_ptr(ptr), m_refCount(new std::atomic<int>(1)) 20 {} 21 22 CSharedPtr(const CSharedPtr& other) 23 { 24 m_ptr = other.m_ptr; 25 m_refCount = other.m_refCount; 26 ++(*m_refCount); 27 } 28 29 ~CSharedPtr() 30 { 31 if (--(*m_refCount) == 0) 32 { 33 Del(m_ptr); 34 Del(m_refCount); 35 } 36 } 37 38 CSharedPtr& operator = (const CSharedPtr& other) 39 { 40 if (this != &other) 41 { 42 if (--(*m_refCount) == 0) 43 { 44 Del(m_ptr); 45 Del(m_refCount); 46 } 47 48 m_ptr = other.m_ptr; 49 m_refCount = other.m_refCount; 50 ++(*m_refCount); 51 } 52 return *this; 53 } 54 55 T* Get() 56 { 57 return m_ptr; 58 } 59 60 int Count() 61 { 62 return m_refCount->load(); 63 } 64 65 T* operator -> () 66 { 67 return Get(); 68 } 69 70 T& operator * () 71 { 72 return *Get(); 73 } 74 75 private: 76 T* m_ptr; 77 std::atomic<int>* m_refCount; 78 }; 79 80 int main() 81 { 82 CSharedPtr<std::string> s(new std::string("hello world")); 83 std::cout << s.Get() << " ref count is " << s.Count() << "\n"; 84 85 { 86 CSharedPtr<std::string> s1(s); 87 std::cout << s.Get() << " ref count is " << s.Count() << "\n"; 88 } 89 std::cout << s.Get() << " ref count is " << s.Count() << "\n"; 90 91 { 92 CSharedPtr<std::string> s1(s); 93 std::cout << s.Get() << " ref count is " << s.Count() << "\n"; 94 CSharedPtr<std::string> s2(s1); 95 std::cout << s.Get() << " ref count is " << s.Count() << "\n"; 96 } 97 std::cout << s.Get() << " ref count is " << s.Count() << "\n"; 98 99 return 0; 100 } 101 102 /* 输出 103 0xf11c30 ref count is 1 104 0xf11c30 ref count is 2 105 0xf11c30 ref count is 1 106 0xf11c30 ref count is 2 107 0xf11c30 ref count is 3 108 0xf11c30 ref count is 1 110 */