C++11新特性——智能指针之shared_ptr

此课件及源代码来自B站up主:码农论坛,该文章仅作为本人学习笔记使用。

1、智能指针shared_ptr

shared_ptr共享它指向的对象,多个shared_ptr可以指向(关联)相同的对象,在内部采用计数机制来实现。

当新的shared_ptr与对象关联时,引用计数增加1。

shared_ptr超出作用域时,引用计数减1。当引用计数变为0时,则表示没有任何shared_ptr与对象关联,则释放该对象。

一、基本用法

shared_ptr的构造函数也是explicit,但是,没有删除拷贝构造函数和赋值函数。

1)初始化

方法一:

shared_ptr<AA> p0(new AA("zq"));     // 分配内存并初始化。

方法二:

shared_ptr<AA> p0 = make_shared<AA>("zq");  // C++11标准,效率更高。

shared_ptr<int> pp1=make_shared<int>();         // 数据类型为int。

shared_ptr<AA> pp2 = make_shared<AA>();       // 数据类型为AA,默认构造函数。

shared_ptr<AA> pp3 = make_shared<AA>("zq");  // 数据类型为AA,一个参数的构造函数。

shared_ptr<AA> pp4 = make_shared<AA>("zq",8); // 数据类型为AA,两个参数的构造函数。

方法三:

AA* p = new AA("zq");

shared_ptr<AA> p0(p);                  // 用已存在的地址初始化。

方法四:

shared_ptr<AA> p0(new AA("zq"));

shared_ptr<AA> p1(p0);                 // 用已存在的shared_ptr初始化,计数加1。

shared_ptr<AA> p1=p0;                 // 用已存在的shared_ptr初始化,计数加1。

2)使用方法

  1. 智能指针重载了*和->操作符,可以像使用指针一样使用shared_ptr
  2. use_count()方法返回引用计数器的值。
  3. unique()方法,如果use_count()为1,返回true,否则返回false
  4. shared_ptr支持赋值,左值的shared_ptr的计数器将减1,右值shared_ptr的计算器将加1。
  5. get()方法返回裸指针。
  6. 不要用同一个裸指针初始化多个shared_ptr
  7. 不要用shared_ptr管理不是new分配的内存。

3)用于函数的参数

unique_ptr的原理相同。

4)不支持指针的运算(+、-、++、--)

二、更多细节

1)将一个unique_ptr赋给另一个时,如果源unique_ptr是一个临时右值,编译器允许这样做;如果源unique_ptr将存在一段时间,编译器禁止这样做。一般用于函数的返回值。

1 ) shared_ptr允许这样做。

2)用nullptrshared_ptr赋值将把计数减1,如果计数为0,将释放对象,空的shared_ptr==nullptr

3release()释放对原始指针的控制权,将unique_ptr置为空,返回裸指针。

3) shared_ptr 不存在释放的操作,控制权不是由一个人说了算的。

4std::move()可以转移对原始指针的控制权。还可以将unique_ptr转移成shared_ptr

5reset()改变与资源的关联关系。

pp.reset();        // 解除与资源的关系,资源的引用计数减1。

pp. reset(new AA("bbb"));  // 解除与资源的关系,资源的引用计数减1。关联新资源。

6swap()交换两个shared_ptr的控制权。

void swap(shared_ptr<T> &_Right);

7shared_ptr也可象普通指针那样,当指向一个类继承体系的基类对象时,也具有多态性质,如同使用裸指针管理基类对象和派生类对象那样。

8shared_ptr不是绝对安全,如果程序中调用exit()退出,全局的shared_ptr可以自动释放,但局部的shared_ptr无法释放。

9shared_ptr提供了支持数组的具体化版本。

数组版本的shared_ptr,重载了操作符[],操作符[]返回的是引用,可以作为左值使用。

10shared_ptr的线程安全性:

  1. shared_ptr的引用计数本身是线程安全(引用计数是原子操作)。
  2. 多个线程同时读同一个shared_ptr对象是线程安全的。
  3. 如果是多个线程对同一个shared_ptr对象进行读和写,则需要加锁。
  4. 多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,都需要加锁保护。

11)如果unique_ptr能解决问题,就不要用shared_ptr。unique_ptr的效率更高,占用的资源更少。

示例1:

#include <iostream>
#include <memory>
using  namespace std;

class AA
{
public:
      string m_name;

      AA() { cout << m_name << "调用构造函数AA()。\n"; }
      AA(const string & name) : m_name(name) { cout << "调用构造函数AA("<< m_name << ")。\n"; }
      ~AA() { cout << "调用了析构函数~AA(" << m_name << ")。\n"; }
};

int main()
{
      shared_ptr<AA> pa0(new AA("zqa"));     // 初始化资源zqa。
      shared_ptr<AA> pa1 = pa0;                       // 用已存在的shared_ptr拷贝构造,计数加1。
      shared_ptr<AA> pa2 = pa0;                       // 用已存在的shared_ptr拷贝构造,计数加1。

      cout << "pa0.use_count()=" << pa0.use_count() << endl;   // 值为3。

      shared_ptr<AA> pb0(new AA("zqb"));    // 初始化资源zqb。
      shared_ptr<AA> pb1 = pb0;                      // 用已存在的shared_ptr拷贝构造,计数加1。
      cout << "pb0.use_count()=" << pb0.use_count() << endl;   // 值为2。

      pb1 = pa1;      // 资源zqa的引用加1,资源zqb的引用减1。
      pb0 = pa1;      // 资源zqa的引用加1,资源zqb的引用成了0,将被释放。

      cout << "pa0.use_count()=" << pa0.use_count() << endl;   // 值为5。
      cout << "pb0.use_count()=" << pb0.use_count() << endl;   // 值为5。
}

2、智能指针的删除器

在默认情况下,智能指针过期的时候,用delete原始指针; 释放它管理的资源。

程序员可以自定义删除器,改变智能指针释放资源的行为。

删除器可以是全局函数、仿函数和Lambda表达式,形参为原始指针。

示例:

#include <iostream>
#include <memory>
using  namespace std;

class AA
{
public:
      string m_name;

      AA() { cout << m_name << "调用构造函数AA()。\n"; }
      AA(const string & name) : m_name(name) { cout << "调用构造函数AA("<< m_name << ")。\n"; }
      ~AA() { cout << "调用了析构函数~AA(" << m_name << ")。\n"; }
};

void deletefunc(AA* a) {    // 删除器,普通函数。
      cout << "自定义删除器(全局函数)。\n";
      delete a;
}

struct deleteclass               // 删除器,仿函数。
{
      void operator()(AA* a) {
            cout << "自定义删除器(仿函数)。\n";
            delete a;
      }
};

auto deleterlamb = [](AA* a) {   // 删除器,Lambda表达式。
      cout << "自定义删除器(Lambda)。\n";
      delete a;
};

int main()
{
      shared_ptr<AA> pa1(new AA("a"), deletefunc);
      //shared_ptr<AA> pa2(new AA("b"), deleteclass());
      //shared_ptr<AA> pa3(new AA("c"), deleterlamb);

      //unique_ptr<AA,decltype(deletefunc)*> pu1(new AA("1"), deletefunc);
    // unique_ptr<AA, void (*)(AA*)> pu0(new AA("1"), deletefunc);
      //unique_ptr<AA, deleteclass> pu2(new AA("2"), deleteclass());
      //unique_ptr<AA, decltype(deleterlamb)> pu3(new AA("3"), deleterlamb);
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智能指针是C++中用于管理动态分配的内存的一种机制。它们可以自动地在不再需要时释放内存,从而避免内存泄漏和悬挂指针的问题。 shared_ptr是一种引用计数智能指针,它可以跟踪有多少个shared_ptr指向同一个对象,并在没有引用时自动释放内存。当创建shared_ptr时,它会增加引用计数,当销毁或重置shared_ptr时,它会减少引用计数。只有当引用计数为0时,才会真正释放内存。\[1\]shared_ptr可以通过构造函数接受一个指向动态分配对象的指针来创建,也可以使用std::make_shared函数来创建。\[2\] unique_ptr是一种独占智能指针,它拥有对动态分配对象的唯一所有权。当unique_ptr被销毁时,它会自动释放内存。unique_ptr不能被复制,但可以通过std::move函数进行转移所有权。\[3\]unique_ptr可以通过构造函数接受一个指向动态分配对象的指针来创建。 weak_ptr是一种弱引用智能指针,它指向由shared_ptr管理的对象,但不会增加引用计数。weak_ptr可以用于解决shared_ptr的循环引用问题,因为它不会导致对象无法释放。\[1\]weak_ptr可以通过shared_ptr的构造函数来创建。 auto_ptr是C++11之前的一种智能指针,它类似于unique_ptr,但有一些限制和问题。auto_ptr在复制时会转移所有权,这可能导致悬挂指针的问题。因此,auto_ptr已经被unique_ptr取代,不推荐使用。 总结来说,shared_ptr是引用计数智能指针,unique_ptr是独占智能指针,weak_ptr是弱引用智能指针,而auto_ptr是已经过时的智能指针。它们各自有不同的用途和特点,可以根据具体的需求选择使用。 #### 引用[.reference_title] - *1* *2* *3* [C++11 解决内存泄露问题的智能指针shared_ptr、unique_ptr、weak_ptr](https://blog.csdn.net/weixin_44120785/article/details/128714630)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值