目录
shared_ptr实现共享式拥有概念。多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。从名字share就可以看出了资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。可以通过成员函数use_count()来查看资源的所有者个数。除了可以通过new来构造,还可以通过传入auto_ptr, unique_ptr,weak_ptr来构造。当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放。
shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占的), 在使用引用计数的机制上提供了可以共享所有权的智能指针。
成员函数:
use_count 返回引用计数的个数
unique 返回是否是独占所有权( use_count 为 1)
swap 交换两个 shared_ptr 对象(即交换所拥有的对象)
reset 放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少
get 返回内部对象(指针), 由于已经重载了()方法, 因此和直接使用对象是一样的.如
shared_ptr<int> sp(new int(1));
sp 与 sp.get()是等价的。
share_ptr的简单例子:
-
- int main(){
- string *s1 = new string("s1");
-
- shared_ptr<string> ps1(s1);
- shared_ptr<string> ps2;
- ps2 = ps1;
-
- cout << ps1.use_count()<<endl; //2
- cout<<ps2.use_count()<<endl; //2
- cout << ps1.unique()<<endl; //0
-
- string *s3 = new string("s3");
- shared_ptr<string> ps3(s3);
-
- cout << (ps1.get()) << endl; //033AEB48
- cout << ps3.get() << endl; //033B2C50
- swap(ps1, ps3); //交换所拥有的对象
- cout << (ps1.get())<<endl; //033B2C50
- cout << ps3.get() << endl; //033AEB48
-
- cout << ps1.use_count()<<endl; //1
- cout << ps2.use_count() << endl; //2
- ps2 = ps1;
- cout << ps1.use_count()<<endl; //2
- cout << ps2.use_count() << endl; //2
- ps1.reset(); //放弃ps1的拥有权,引用计数的减少
- cout << ps1.use_count()<<endl; //0
- cout << ps2.use_count()<<endl; //1
- }
引用计数不是垃圾回收,引用计数能够尽快收回不再被使用的对象,同时在回收的过程中也不会造成长时间的等待, 更能够清晰明确的表明资源的生命周期。
std::shared_ptr 是一种智能指针,它能够记录多少个 shared_ptr 共同指向一个对象,从而消除显式的调用 delete,当引用计数变为零的时候就会将对象自动删除。
但还不够,因为使用 std::shared_ptr 仍然需要使用 new 来调用,这使得代码出现了某种程度上的不对称。
std::make_shared 就能够用来消除显式的使用 new,所以 std::make_shared 会分配创建传入参数中的对象, 并返回这个对象类型的 std::shared_ptr 指针。例如:
- #include <iostream>
- #include <memory>
- void foo(std::shared_ptr<int> i)
- {
- (*i)++;
- }
- int main()
- {
- // auto pointer = new int(10); // illegal, no direct assignment
- // Constructed a std::shared_ptr
- auto pointer = std::make_shared<int>(10);
- foo(pointer);
- std::cout << *pointer << std::endl; // 11
- // The shared_ptr will be destructed before leaving the scope
- return 0;
- }
std::shared_ptr 可以通过 get() 方法来获取原始指针,通过 reset() 来减少一个引用计数, 并通过 use_count() 来查看一个对象的引用计数。例如:
- auto pointer = std::make_shared<int>(10);
- auto pointer2 = pointer; // 引用计数+1
- auto pointer3 = pointer; // 引用计数+1
- int *p = pointer.get(); // 这样不会增加引用计数
- std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 3
- std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; // 3
- std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 3
-
- pointer2.reset();
- std::cout << "reset pointer2:" << std::endl;
- std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 2
- std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; // 0, pointer2 已 reset
- std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 2
- pointer3.reset();
- std::cout << "reset pointer3:" << std::endl;
- std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 1
- std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; // 0
- std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 0, pointer3 已 reset
std::unique_ptr
std::unique_ptr 是一种独占的智能指针,它禁止其他智能指针与其共享同一个对象,从而保证代码的安全:
std::unique_ptr |
make_unique 并不复杂,C++11 没有提供 std::make_unique,可以自行实现:
template |
至于为什么没有提供,C++ 标准委员会主席 Herb Sutter 在他的博客中提到原因是因为『被他们忘记了』。
既然是独占,换句话说就是不可复制。但是,我们可以利用 std::move 将其转移给其他的 unique_ptr,例如:
#include |
3 link
C++11中提供了三种不同类型的智能指针,分别是:
共享智能指针std::shared_ptr独占智能指针std::unique_ptr弱智能指针std::weak_ptr
共享智能指针使用引用计数,每个shared_ptr的拷贝都指向相同的内存,在最后一个shared_ptr被析构的时候,内存被释放。
初始化共享智能指针
初始化共享智能指针有两种方法,第一种是通过new来直接初始化,第二种方式是通过make_shared方法与reset方法来初始化,这部分的代码演示如下:
- // make_shared初始化
- int a = 1;
- std::shared_ptr<int> a1 = std::make_shared<int>(a);
- std::cout << "a1: "<<*a1 << std::endl;
- // 直接初始化
- std::shared_ptr<int> a2 = std::shared_ptr<int>(new int(2));
- std::cout << "a2: " << *a2 << std::endl;
一个原始指针最多只能初始化一个智能指针、而且可以从智能指针中通过get方法获取原始指针,这部分的代码演示如下:
- // 一个原始指针,只能初始化一个智能指针
- int* ptr = new int(12);
- std::shared_ptr<int> a3(ptr);
- // std::shared_ptra4(ptr); //直接挂了!
-
- // 从智能指针中获取原始指针
- int* pp = a3.get();
- std::cout << "pp: " << *pp << std::endl;
共享智能指针的代码演示
下面是共享智能指针一个典型的应用场景,就是在std::vector中使用共享智能指针来管理容器的对象或者数据。假设有个结构体,对象如下:
typedef struct person { std::string name; int age;};
然后初始化std::vector如下:
- std::vector<person> persons;
- person p3;
- p3.name = "opencv4";
- p3.age = 20;
- person p4;
- p4.name = "opencv5";
- p4.age = 21;
- persons.emplace_back(p3);
- persons.emplace_back(p4);
然后有一天有个经常写C#或者Java的人,想更新std::vector结构体里面的属性值,于是它就遍历每个元素,然后开始修改,代码如下:
for (auto item : persons) { // 修改的是副本 item.age = 24;}
测试运行结果如下:
for (auto item : persons) { std::cout << "item.age: " << item.age << std::endl;}

发现翻车了,原因是C++来说,通过for直接修改的不是引用,而是修改了副本!这个时候,只要改一个地方就立刻好了:
- for (auto &item : persons) { // 获取引用地址
- item.age = 24;
- }
- for (auto item : persons) {
- std::cout << "item.age: " << item.age << std::endl;
- }

改用智能指针
在初始化时候使用共享智能指针来完成元素组装,代码演示如下:
- std::vector<std::shared_ptr<person>> pps;
- person x;
- auto p5 = std::make_shared<person>(x);
- p5->name = "make_shared";
- auto p1 = std::shared_ptr<person>(new person());
- auto p2 = std::shared_ptr<person>(new person());
- p1->age = 12;
- p1->name = "qing";
- p2->age = 32;
- p2->name = "zhigang";
- pps.emplace_back(p1);
- pps.emplace_back(p2);
- pps.emplace_back(p5);
- for (auto item : pps) {
- item->age = 24;
- }
- for (auto item : pps) {
- std::cout << "item->name: " << item->name << " item->age:" << item->age << std::endl;
- }
运行结果如下:

最后,推荐使用make_shared来初始化共享智能指针!
unique_ptr因为其局限性(独享所有权),一般很少用于多线程操作。在多线程操作的时候,既可以共享资源,又可以自动释放资源,这就引入了shared_ptr。
shared_ptr为了支持跨线程访问,其内部有一个引用计数(线程安全),用来记录当前使用该资源的shared_ptr个数,在结束使用的时候,引用计数为-1,当引用计数为0时,会自动释放其关联的资源。
特点 相对于unique_ptr的独享所有权,shared_ptr可以共享所有权。其内部有一个引用计数,用来记录共享该资源的shared_ptr个数,当共享数为0的时候,会自动释放其关联的资源。
对比unique_ptr,shared_ptr不支持数组,所以,如果用shared_ptr指向一个数组的话,需要自己手动实现deleter,如下所示:
| 1 |
|
make_shared函数是最安全分配和使用动态内存的方法,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。
shared_ptr<int> p3 = make_shared<int>(42);//指向一个值为42的int的shared_ptr;
智能指针是模板,当我们创建一个智能指针时候,必须提供额外信息------指针可以指向的类型,与vector一样,我们在<>中给出类型,之后就是所定义的这种智能指针的名字: