概述
场景一: 希望指向多个指针管理一片空间
unique_ptr它是不允许两个智能指针管理一片空间的,所以其禁止直接拷贝和赋值(转化为右值可以)。
auto_ptr虽然其允许我们多个智能指针管理一片空间,但是这样的操作对于auto_ptr来说是不安全的,因为一个智能指针释放空间时,是不管别的指针的。
但是,我们有时候是希望,使用多个指针来指向同一片空间的,这样unique_ptr无法实现,auto_ptr又不安全,所以c++11又增加了shared_ptr,它是允许我们使用多个智能指针管理一片空间的。
场景二: 作为容器的类型前面说到unique_ptr和auto_ptr作为容器的类型的时候,是无法满足容器的特性的(就是两个元素之间赋值),但是shared_ptr是支持的。
shared_ptr原理
智能指针中使用引用计数的方式来判断是否需要释放智能指针指向的动态的空间。
shared_ptr内部使用引用计数的方式,每一片空间都有一个引用计数,每有一个指针指向这片空间,那么其引用计数就会加1,有指针不指向它了,其引用计数就会减1。
当智能指针管理的空间的引用计数为0的时候,就会释放这块内存。所以使用shared_ptr指向同一片空间,是不会出现一个释放影响别的指针使用的,因为一个指针不使用,其只会影响引用计数,只有当智能指针释放的时候,空间的引用计数也减为0了,那么就会释放这块空间。(也就是只有一个智能指针管理这块空间时,当智能指针释放,这块空间也就释放了)
注意事项(适用于所有智能指针)
我们不能随便将一块地址让智能指针进行管理,只能将动态开辟的空间让它去管理。
比如: int a = 10;auto_ptr<int> p1(&a); // error;
千万注意上面这样的代码,因为我们智能指针的析构函数是使用delete来释放空间的,也就是说其管理的应该是动态开辟的空间,如果像上面那样写,会导致delete释放非堆内存,这显然不对。
1. 定义shared_ptr的对象
- unique_ptr<类型> p1(new 空间); // 类型: 智能指针指向的类型,空间:智能指针管理的空间
- std::shared_ptr<int> p1;
std::shared_ptr<int> p1(NULL); // 创建指向空的智能指针,注意,此时其引用计数为 0(因为没有指向空间)- std::shared_ptr<int> p1(new int()); // p1直系那个一片空间,引用计数+1
- 使用auto_ptr,unique_ptr,shared_ptr的临时对象初始化
std::shared_ptr<int> p1(std::unique_ptr<int> (new int)); // 执行完这行unique_ptr的指针 就释放了
std::shared_ptr<int> p1(std::shared_ptr<int> (new int));
std::shared_ptr<int> p1(std::auto_ptr<int> (new int));- int a = new int();
std::shared_ptr<int> p1(&a);
2. 多个指针指向同一块空间
- 拷贝构造
std::shared_ptr<int> p1(new int());
std::shared_ptr<int> p2(p1);
- 赋值 -- 所以其可以作为容器的类型,其更加符合容器的要求(一个元素可以赋值给另外一个元素)
std::shared_ptr<int> p1(new int());
std::shared_ptr<int> p2;
p2 = p1;
例子:std::shared_ptr<int> p1(new int(10)); // p1指向空间,引用计数+1(为1)
{
std::shared_ptr<int> p2;
p2 = p1; // 指针p2和p1指向了同一片空间(引用计数加1(为2)),在大括号结束之后,p2被 释放,引用计数减1(为1)。
}
std::cout << *p1 << std::endl; // 由于p2释放后引用计数为1,所以空间没有释放,所以此时 访问空间数据没有问题。
当然,当p1析构,那么引用计数就变成0了,那么就释放掉此空间。
3. shared_ptr的函数
1)use_count()函数
- long use_count();
我们前面说到,共享指针基于引用计数来实现多个指针管理一片空间的,那我们如何知道当前的指针指向的空间被多少的指针指向。
我们可以使用use_count(),这个函数返回当前指针指向空间的引用计数是多少。
代码:
int main(void) {std::shared_ptr<int> p1(new int(10));{std::shared_ptr<int> p2(p1);std::cout << p2.use_count() << std::endl; // 输出2}std::cout << p1.use_count() << std::endl; // 输出1std::cin.get();
}
2) unique()函数
- bool unique(); // 用来判断,当前指针指向其管理空间的是否只有它(引用计数是否为1),如果是返回true,如果不是返回false。
代码:
std::shared_ptr<int> p1(new int(10));
if (p1.unique()) { // 返回truestd::cout << "引用计数为1" << std::endl; // 正常输出
}
3)swap(),get(),release()函数
- T* get(p); // 返回智能指针指向的空间地址
- void p.reset(地址); // 重新设置智能指针指向的空间地址
- T* release(p); // 将管理空间的权限重到我们手中
当然这些函数和auto_ptr的用法一样,那里我们进行了详细的描述。
4. 内置类型element_type
表示当前智能指针指向的数据的类型,我们在使用智能指针数据的时候,可以直接使用此类型来统一表示,并不用去关心其具体指向什么类型。
std::shared_ptr<int>::element_type t = 10;