为什么有智能指针
在写程序的时候,经常会使用堆中的内存,但是又特别容易忘记释放这块内存,这就会造成内存泄露。但在我们日常的小编程中,尽管内存泄露,也不会影响我们的程序。这可是一个隐患,在编写大程序的时候容易造成程序崩溃。为了解决这个问题,标准库提供了智能指针类型。功能类似于常规指针,但智能的一点是–当没有指针指向该对象时,会自动释放该对象所占用的堆内存。这就极大的避免程序员因为忘记释放内存而造成内存泄露。
那么我们为什么会使用动态内存呢 ?
- 我们不知道程序会使用多少对象。这时数组肯定不能使用了,你只能在程序运行的时候来决定创建多少个对象。
- 程序不知道所需对象的准确类型。
- 程序需要多少个对象间共享数据。
shared_ptr:允许多个指针指向同一个对象
unique_ptr:独占所指向的对象
weak_ptr: 指向 shared_ptr所管理的对象
如何使用shared_ptr
shared_ptr类
初始化一个 int 类型,name = p1 的智能指针,保存着空指针的智能指针
shared_ptr<int> p1;
判断 p1 是否为空
if(p1 && p1->empty()) *p1 = 1;
操作 | 意义 |
---|---|
shared_ptr p | 空智能指针,可以指向类型为 T 的对象 |
p | 将 p 用作一个条件判断,若p指向一个对象,则为true |
*p | 解引用p,获得它指向的对象 |
swap(p,q) | 交换 p 和 q 中的指针 |
p.unique() | 若p.use_count() 为1,返回true,否则返回 false |
p.use_count() | 返回与p共享的智能指针的数量 |
p.get() | 返回 p 总保存的指针 |
make_shared 函数
创建一个智能指针。
make_shared 函数的返回值为 shared_ptr 类型。
用默认初始化函数初始化一个int类型的智能指针,name = p。默认初始化的值为 0。
auto p = make_shared<int>();
shared_ptr 的拷贝和赋值
智能指针有一个关联的计数器,每当拷贝一个智能指针的时候,计数器就会增加 1,如果 我们给一个shared_ptr 赋予一个新值的时候,就把的计数器数值 减1,或者 一个shared_ptr 离开了原先的作用域,也就是该shared_ptr 被销毁的时候,计数器也会减 1。
测试样例如下:
int main()
{
auto p =std::make_shared<int>(42); // p指向的对象只有 p 一个引用
use_cout() //方法返回的是与该指针共享对象的智能指针数量
std::cout << p.use_count() << std::endl; // 1
{
auto q(p);
std::cout << p.use_count() << std::endl; // 2
}
std::cout << p.use_count() << std::endl; // 1
return 0;
}
和结果一样,如果我们用一个shared_ptr 初始化另外一个shared_ptr,就如测试一样,用p 初始化 q,则p的引用计数 + 1,离开了作用 q 的作用域,也就是 q 自动销毁,则p 的引用计数 - 1
shared_ptr自动销毁
当一个shared_ptr 的计数器的值为 0时,也就是没有智能指向该对象的时候,shared_ptr 会自动调用其析构函数,通过析构函数来释放对象所分配的资源。
shared_ptr 与内置指针的隐式转化
由于shared_ptr 的构造函数被声明为explicit(禁止隐式转换声明),所以 内置指针和智能指针都是禁止隐式转换的。
不要使用相同的内置指针初始化多个智能指针。
#include <iostream>
#include <memory>
using namespace std;
int main()
{
int *p = new int(1);
shared_ptr<int> p1(p);
{
shared_ptr<int> p2(p);
cout << *p1 << endl; // 1
}
cout << *p1 << endl; //0
return 0;
}
如果使多个独立创建的智能指针指向同一块内存,若有一个智能指针被销毁了,那么其他的指针所指向的内存已经被释放。
参考书籍 c++ Primer