智能指针
在 C++ 库中最重要的类模板之一
智能指针实际上是将指针封装在一个类里, 通过对象来管理指针.
STL 中的智能指针 auto_ptr
头文件: <memory>
生命周期结束时, 自动摧毁指向的内存空间
不能指向堆数组(因为 auto_ptr 的析构函数删除指针用的是 delete, 而不是 delete[])
auto_ptr 的构造函数为 explicit 类型, 所以只能显示初始化, 比如:
auto_ptr<int> ap1(new int(1)); // 初始化正确, 创建 ap1 类模板对象, 使类模板里的指针为 int * 型, 并指向 1 的地址
int* p = new int(1);
- auto_ptr<int> ap2(p); // 初始化正确
- // auto_ptr<int> ap3 = new int(2); // 出错, 不能隐式初始化
提供 get()成员函数, 可以用来查看类里的指针地址. 比如:
- auto_ptr<int> ap(new int(1));
- cout<<ap.get()<<endl; // 打印数值 1 的地址 : 0x6d2d18
- int *p =ap.get();
- cout<< *p<<endl; // 打印数值 1
一片堆空间只属于一个智能指针对象
当 auto_ptr 被拷贝或赋值后, 则自身的指针指向的地址会被抢占, 比如:
- auto_ptr<int> p1(new int(1));
- auto_ptr<int> p2(new int(2));
- p1 =p2; // 首先会 delete p1 对象的类成员指针, 然后将 p2 对象的类成员指针赋值给 p1, 最后修改 p2 指针地址为 NULL
- cout<<"p2 ="<<p2.get()<<endl; // 打印 : p2=0
- //cout<<*p2<<endl; // 出错, 因为 p2=0
初探 auto_ptr 智能指针
- #include <iostream>
- #include <memory>
- using namespace std;
- class Test
- {
- public:
- int mvalue;
- Test(int i=0)
- {
- mvalue=i;
- cout<<"Test("<<mvalue<<")"<<endl;
- }
- ~Test()
- {
- cout<< "~Test("<<mvalue<<")"<<endl;
- }
- };
- void func() // 在 func 函数里使用 auto_ptr
{
- auto_ptr<Test> p1(new Test(1));
- cout<<"p1 ="<<p1.get()<<endl;
- cout<<endl;
- auto_ptr<Test> p2(new Test(2));
- cout<<"p2 ="<<p2.get()<<endl;
- cout<<endl;
- cout<<"p1=p2"<<endl;
- p1=p2;
- cout<<endl;
- cout<<"p1 ="<<p1.get()<<endl;
- cout<<"p2 ="<<p2.get()<<endl;
- }
- int main()
- {
- cout<<"*****begin*****"<<endl;
- func();
- cout<<"*****end*****"<<endl;
- return 0;
- }
运行打印:
- *****begin*****
- Test(1)
- p1 =0x8db1008
- Test(2)
- p2 =0x8db1018
- p1=p2
- ~Test(1)
- p1 =0x8db1018
- p2 =0
- ~Test(2)
- *****end*****
从结果可以看到, 由于 func()的生命周期结束, 所以里面的 auto_ptr 指针自动就被释放了.
可以发现在调用 p1=p2 时, 首先会 delete p1 对象的类成员指针 (调用~ Test(1) 析构函数), 然后将 p2 对象的类成员指针赋值给 p1(p1=0x8db1018), 最后修改 p2 指针地址为 NULL(p2 =0).
STL 中的智能指针 shared_ptr(需要 C++11 支持)
带有引用计数机制, 支持多个指针对象指向同一片内存(实现共享)
提供 swap()成员函数, 用来交换两个相同类型的对象, 比如:
- shared_ptr<int> p1(new int(1));
- shared_ptr<int> p2(new int(2));
- p1.swap(p2); // 交换后 p1=2,p2=1
- cout<<*p1 <<endl; // 打印 2
- cout<< *p2 <<endl; // 打印 1
提供 unique()成员函数, 判断该指针对象地址是否被其它指针对象引用
提供 get()成员函数, 用来获取指针对象指向的地址
提供 reset()成员函数, 将自身指针对象地址设为 NULL, 并将引用计数 - 1(当计数为 0, 会自动去 delete 内存)
提供 use_count()成员函数, 可以用来查看引用计数个数, 比如:
- shared_ptr<int> sp1(new int(30)); // 计数 + 1
- cout<<sp1.use_count()<<endl; // 打印计数: 1
- cout<<sp1.unique()<<endl; // 打印: 1
- shared_ptr<int> sp2(sp1); // 计数 + 1
- cout<<sp1.use_count()<<endl; // 打印: 2
- cout<<sp1.unique()<<endl; // 由于 sp1 指针对象被 sp2 引用, 打印: 0
- sp1.reset(); // 将 sp1 指针对象地址设为 NULL, 计数 - 1
- cout<<sp1.get()<<endl; //sp1 指针对象地址为 NULL, 打印: 0
- cout<<sp2.use_count()<<endl; // 打印: 1
- cout<<sp2.unique()<<endl; // 由于 sp1 释放, 仅剩下 sp2 指向 30 所在的地址, 所以打印: 1
初探 shared_ptr 智能指针(以上个 Test 类为例分析)
- #include <iostream>
- #include <memory>
- using namespace std;
- class Test
- {
- public:
- int mvalue;
- Test(int i=0)
- {
- mvalue=i;
- cout<<"Test("<<mvalue<<")"<<endl;
- }
- ~Test()
- {
- cout<< "~Test("<<mvalue<<")"<<endl;
- }
- };
- int main()
- {
- cout<<"*****begin*****"<<endl;
- shared_ptr<Test> p1(new Test(1));
- shared_ptr<Test> p2(p1);
- cout<<"*p1="<<p1->mvalue<<","<<"*p2="<<p2->mvalue<<endl;
- p1.reset();
- p2.reset();
- cout<<"count:"<<p2.use_count()<<endl;
- cout<<"*****end*****"<<endl;
- return 0;
- }
运行打印:
- *****begin*****
- Test(1)
- *p1=1, *p2=1
- ~Test(1)
- count:0
- *****end*****
从结果可以看到, 我们把 p1 和 p2 都释放了后, 由于 count=0, 便自动去 delete Test 指针了.
STL 中的其它智能指针(在后面学习到, 再来深入描述)
-weak_ptr
配合 shared_ptr 而引入的一种智能指针
-unique_ptr
只能一个指针对象指向一片内存空间(和 auto_ptr 类似), 但是不能被拷贝和赋值(实现唯一性)
QT 中的智能指针(在后面学习到, 再来深入描述)
-QPointer
头文件 < QPointer>
当其指向的对象被销毁时, 他会被自动置空(避免被多次释放和野指针)
缺点在于, 该模板类析构时, 不会自动摧毁所指向的对象(需要手工 delete)
-QSharedPointer
头文件 < QSharedPointer>
带有引用计数机制, 支持多个指针对象指向同一片内存(实现共享)
可以被自由地拷贝和赋值
当引用计数为 0(最后一个指针被摧毁)时, 才删除指向的对象(和 shared_ptr 类似)
来源: https://www.cnblogs.com/lifexy/p/8798415.html