C++智能指针
参考链接
裸指针
非动态申请内存地址,函数运行结束编译器自动释放
1 2 3 4
| void func(){ int a = 100; int* p = &a; }
|
动态申请内存地址,函数结束也不会释放
但是也无法访问该内存地址,造成内存泄漏
1 2 3 4
| void func1(){ int *p = new int; }
|
c++为了追求性能,没有在语言层面上的垃圾回收功能
shared_ptr
共享指针会记录有多少个共享指针指向同一个物体
当数字降为0时,程序会自动释放这个物体
使用智能指针需要加上
创建一个class
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Ball{ public: Ball(){ cout << "A ball appears" << endl; } ~Ball(){ cout <<"A ball disappears" <<endl; } void Bounce(){ cout <<"A ball jumps" << endl; } };
|
创建三个shared_ptr
指向Ball
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int main(){ shared_ptr<Ball> p = make_shared<Ball>(); cout << p.use_count() << endl; shared_ptr<Ball> p2 = p; cout << p.use_count() << " " <<p2.use_count() << endl; shared_ptr<Ball> p3 = p; cout << p.use_count() << " " << p2.use_count() << " " <<p3.use_count() << endl; p.reset(); cout << p.use_count() << " " << p2.use_count() << " " <<p3.use_count() << endl; p2.reset(); cout << p.use_count() << " " << p2.use_count() << " " <<p3.use_count() << endl; p3.reset(); cout << p.use_count() << " " << p2.use_count() << " " <<p3.use_count() << endl; return 0; }
|
运行结果如下
可以看到当所有shared_ptr
都重置后
原指针指向的Ball
就自动释放了
引用计数
创建一个共享指针指向物体,引用计数会计算当前指向该物体的共享指针个数。
当引用计数为0时,程序自动释放这个物体,防止出现内存泄漏
同时使用裸指针
如果仍然需要获得指向物体的裸指针可以使用get()
方法
但是当所有共享指针被销毁时,裸指针仍然存在,资源也会释放
应尽量避免裸指针和共享指针混用
unique_ptr
0开销,独占某个资源,不支持复制操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include<iostream> #include<memory> using namespace std;
class Ball{ public: Ball(){ cout << "A ball appears" << endl; } ~Ball(){ cout <<"A ball disappears" <<endl; } void Bounce(){ cout <<"A ball jumps" << endl; } };
void func(){ cout << "Now in func" <<endl; unique_ptr<Ball> up {make_unique<Ball>()}; up->Bounce(); cout << "Quit func" <<endl; }
int main(){ cout << "Now in main" <<endl; func(); cout << "Quit main" <<endl; return 0; }
|
运行结果如下:
unique_ptr销毁时资源会自动进行释放
其他用法:
get()
和reset()
用法和shared_ptr
一致
可以使用release()
和已绑定资源解绑
release()
返回资源裸指针
1 2 3 4
| Ball* ball = up.release(); delete ball; ball = nullptr
|
使用release()
和move()
转移控制权
1 2 3 4
| unique_ptr<int> up1 = make_unique<int>(100); unique_ptr<int> up2(up1.release());
unique_ptr<int> up2 = move(up1);
|
weak_ptr
shared_ptr的伴侣,它是shared_ptr的观察者,对资源的引用为非拥式
没有资源的管理权限,不能控制资源释放
访问资源的时候需要通过shared_ptr
weak_ptr仅用于检查资源是否存在,不用于控制资源
使用场景
环形依赖的情况下,使用shared_ptr可能会造成内存泄漏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include<iostream> #include<memory> using namespace std;
struct School;
struct Teacher{ string name; int age; shared_ptr<School> school; ~Teacher(){ cout << "Teacher Destructed." <<endl; } };
struct School(){ string name; shared_ptr<Teacher> principal; ~ }
int main(){ auto principal = make_shared<Teacher>(); auto university = make_shared<School>(); principal->school = university; university->principal = principal; return 0; }
|
运行程序可以看到控制台什么都没有打印,
说明该对象在程序运行结束时没有被销毁
原因:因为当程序执行到principal->school = university;
时
下面university
中的shared_ptr
仍然指向principal
另一个对象同理,他们的引用计数都没有降为0,所以不会自动销毁
使用weak_ptr解决环形依赖问题
只需要将Teacher
类中的 shared_ptr
改为 weak_ptr
即可
运行程序可以看到两个对象被正常释放
注意事项
智能指针是C++11的新功能
需要在编译器加入C++11命令