- 指针的危害
指针未初始化
野指针
内存泄漏
智能指针的出现就是为了解决上面的问题。
智能指针基于这样的事实得以发挥作用:定义在栈中的智能指针,当超出其作用域时,会自动调用它的析构函数,从而可以释放其关联的内存资源。
| 智能指针 | 进入C++标准的版本 | STL头文件 | boost头文件 | 说明 |
|---|---|---|---|---|
| auto_ptr | C++03 | 尽量避免使用 | ||
| unique_ptr | C++11 | 管理单个堆内存对象,独享所有权,不允许赋值和拷贝,不能用于管理数组对象 | ||
| shared_ptr | C++11 | 引用计数智能指针,共享所有权 | ||
| weak_ptr | C++11 | shared_ptr的观察者,只进行引用而不改变引用计数,用来解决shared_ptr的循环引用问题 | ||
| scoped_ptr | - | - | 作用域智能指针,功能与unique_ptr相似。 |
- 本质:
将指针封装为类对象成员,并在析构函数里删除指针指向的内存。 - 不同:
auto_ptr、unique_ptr、scoped_ptr马上删除。
shared_ptr计数为0删除。
weak_ptr不删除。
- 作用
对作用域内的动态分配对象的自动释放 - 基本类型
#include#include using namespace std; int main(){ int* pn = new int(10); auto_ptr ap(pn); cout << *ap << endl; }
- 类类型
#include#include using namespace std; class Test{ public: Test(){cout << __func__ << endl;} ~Test(){cout << __func__ << endl;} void Func(){cout << __func__ << endl;} }; int main(){ Test* pt = new Test; auto_ptr apt(pt); apt->Func(); }
- 缺陷
(1)两个auto_ptr不能同时拥有同一个对象
#includeusing namespace std; int main(){ int* pn = new int(10); auto_ptr ap1(pn); auto_ptr ap2(pn); }
(2)auto_ptr不能管理数组指针
#includeusing namespace std; int main(){ int *pa=new int[10]; auto_ptr ap(pa); }
(3)auto_ptr被拷贝或被赋值后,失去对原指针的管理,这种情况被称为指针所有权传递。
a)赋值的情况
- 实例
#include#include using namespace std; int main(){ int* p = new int(10); auto_ptr ap1(p); cout<< *ap1 < ap2=ap1; cout<< *ap1 < b)拷贝的情况
- 实例
#include#include using namespace std; void Func(auto_ptr ap){ cout << *ap << endl; } int main(){ int* p = new int(10); auto_ptr ap(p); cout<< *ap < #include #include using namespace std; int main(){ int*p = new int(10); auto_ptr ap(p); vector > vec; vec.push_back(ap); }
(4)auto_ptr不能作为容器对象,因为STL容器中的元素经常要支持拷贝,赋值等操作。#include#include #include using namespace std; int main(){ int*p = new int(10); auto_ptr ap(p); vector > vec; vec.push_back(ap); }
- 实例
#include#include using namespace std; class Test{ public: Test(){cout << __func__ << endl;} ~Test(){cout << __func__ << endl;} void func(int n)const{ cout << n << endl; } }; namespace MySTL{ template class auto_ptr{ T* p; public: auto_ptr(T* p):p(p){} ~auto_ptr(){ delete p; } T* operator->(){ return p; } T& operator*(){ return *p; } }; }; int main(){ Test* pp = new Test; MySTL::auto_ptr p(new Test); //p智能指针 p->func(10); p.operator->()->func(100); //p.operator->()返回的是p指针 (*p).func(100); delete pp; int* arr = new int [10]; delete [] arr; } 结果:
Test Test 10 100 100 ~Test ~Test分析:将指针封装为类对象成员,并在析构函数里删除指针指向的内存。
5.3 unique_ptr5.4 scoped_ptr
- 作用
代替auto_ptr,不可复制与赋值。5.5 shared_ptr
- 作用
与unique_ptr相似,在本作用域中使用,不能复制与赋值。
作用
解决unique_ptr禁用拷贝以及auto_ptr的缺陷实例
#include#include using namespace std; class Test { public: Test() { cout << __func__ << endl; } ~Test() { cout << __func__ << endl; } void func(int n)const { cout << n << endl; } }; namespace MySTL { template class auto_ptr { T* p; public: auto_ptr(T* p):p(p) {} ~auto_ptr() { delete p; } T* operator->() { return p; } T& operator*() { return *p; } }; template class shared_ptr { struct Record { T* p; int count; }; Record* record; public: shared_ptr(T* p) { record = new Record{p,1}; } shared_ptr(const shared_ptr& ptr) { record = ptr.record; ++record->count; } T* operator->() { return record->p; } T& operator*() { return *(record->p); } shared_ptr& operator=(const shared_ptr& ptr) { if(this == &ptr) return *this; if(record->p == ptr.record->p) return *this; --record->count; if(record->count == 0) { delete record->p; delete record; } record = ptr.record; ++record->count; return *this; } ~shared_ptr() { --record->count; if(0 == record->count) { delete record->p; delete record; } } }; }; int main() { // Test* pp = new Test; MySTL::shared_ptr p(new Test); //p智能指针 p->func(10); p.operator->()->func(100); //p.operator->()返回的是p指针 (*p).func(100); // delete pp; // int* arr = new int [10]; // delete [] arr; MySTL::shared_ptr p2 = p; p2->func(300); p->func(400); MySTL::shared_ptr p3(new Test); p3 = p; p3->func(500); } 结果:
Test 10 100 100 300 400 Test ~Test 500 ~Test分析:
通过加入Record记录指向该块内存的指针数量,在析构时候避免重复释放内存。
- 存在的问题:循环引用问题
- 实例
#include#include using namespace std; class A; class B; class A{ public: shared_ptr pb; A (){ cout << __func__ << endl; } ~A (){ cout << __func__ << endl; } }; class B{ public: shared_ptr pa; B (){ cout << __func__ << endl; } ~B (){ cout << __func__ << endl; } }; int main(){ shared_ptr a(new A); shared_ptr b(new B); //A和B出现循环引用 a->pb = b; b->pa = a; } 结果:
A B分析:
5.6 weak_ptr
只构造不析构,A和B出现循环引用
- 作用
解决shared_ptr循环引用问题- 实例
#include#include using namespace std; class A; class B; class A{ public: weak_ptr pb; A (){ cout << __func__ << endl; } ~A (){ cout << __func__ << endl; } }; class B{ public: weak_ptr pa; B (){ cout << __func__ << endl; } ~B (){ cout << __func__ << endl; } }; int main(){ shared_ptr a(new A); shared_ptr b(new B); //A和B出现循环引用 a->pb = b; b->pa = a; } 结果:
A B ~B ~A智能指针weak_ptr主要用来协助shared_ptr。不参与引用计数,但是有以下好处:
5.7 总结
1 打破递归的依赖关系
2 使用一个共享的资源但是不要所有权,不添加引用计数
3 避免悬空指针。
- 智能指针的特点
智能指针 管理同一个对象 可拷贝 可复制 所有权 成为容器元素 管理数组指针 auto_ptr NG OK OK 传递 NG NG unique_ptr NG NG NG 独享 NG NG scoped_ptr NG NG NG 独享 NG NG shared_ptr NG OK OK 共享 OK NG weak_ptr NG OK OK 共享 OK NG 虽然通过弱引用指针可以有效的解除循环引用,但这种方式必须在程序员能预见会出现循环引用的情况下才能使用,也可以是说这个仅仅是一种编译期的解决方案。
如果程序在运行过程中出现了循环引用,还是会造成内存泄漏的。
因此,不要认为只要使用了智能指针便能杜绝内存泄漏。



