C++11智能指针

为了解决C++内存泄漏的问题,C++11引入了智能指针(SmartPointer)。智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,C++中有一个重要原则,在函数结束

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

  为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer)。

  智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,C++中有一个重要原则,在函数结束时(不论是正常返回,还是因为异常除法的对战回退),会将所有栈对象销毁,也就是会调用所有栈对象的析构函数。智能指针内部保存的内存也就被释放掉了(除非将智能指针保存起来)。

  C++11提供了三种智能指针:std::shared_ptr, std::unique_ptr, std::weak_ptr,使用时需添加头文件<memory>。

  shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。shared_ptr内部的引用计数是安全的,但是对象的读取需要加锁。

1. shared_ptr

1.1 基本用法

(1)初始化

  可以通过构造函数、std::make_shared<T>辅助函数和reset方法来初始化shared_ptr

#include "stdio.h"
#include<memory>
#include<iostream>
using namespace std;

void main()
{
    shared_ptr<int> p1(new int(10));
    cout << "p1的引用计数:"<<p1.use_count() << endl;
    shared_ptr<int> p2 = p1; 
    cout << "p1的引用计数:" << p1.use_count() << " p2的引用计数:" << p2.use_count() << endl;
    p2.reset(new int(2));   // 当智能指针中有值时,调用rest会使引用计数减1
    cout << "p1的引用计数:" << p1.use_count() << " p2的引用计数:" << p2.use_count() << endl;
    cout << *p2 << endl;
    p2.reset(); 
    cout << "p1的引用计数:" << p1.use_count() << " p2的引用计数:" << p2.use_count() << endl;

    shared_ptr<int> p3 = make_shared<int>(20); 
    shared_ptr<int> p4;
    p4.reset(new int(30));
    cout << "p4的引用计数:" << p4.use_count() << endl;
}

注意:不能将一个原始指针直接赋值给一个智能指针

std::shared_ptr<int> p4 = new int(1);// error

  reset()包含两个操作。当智能指针中有值的时候,调用reset()会使引用计数减1.当调用reset(new xxx())重新赋值时,智能指针首先是生成新对象,然后将就对象的引用计数减1(当然,如果发现引用计数为0时,则析构旧对象),然后将新对象的指针交给智能指针保管。

(2)获取原始指针

std::shared_ptr<int> p4(new int(5));
int *pInt = p4.get();

(3)指定删除器

  智能指针可以指定删除器,当智能指针的引用计数为0时,自动调用指定的删除器来释放内存。std::shared_ptr可以指定删除器的一个原因是其默认删除器不支持数组对象,这一点需要注意。

template<class T, class D>
shared_ptr(T *p, D d)
void DeleteIntPtr(int *p)
{
     delete p;      
}

shared_ptr<int> p(new int(1), DeleteIntPtr);

  当我们使用shared_ptr管理动态数组时,需要指定删除器,因为std::shared_ptr的默认删除器不支持数组对象

shared_ptr<int> p(new int[10], [](int *p){delete[] p;});

  也可以使用syd::default_delete作为删除器,default_delete的内部是通过调用delete来实现的

shared_ptr<int> p(new int[10], deault_delete<int[]>);

(4)注意make_share和make_arrar_share的使用

(5)使用shared_ptr注意事项

a. 不要用一个原始指针初始化初始化多个shared_ptr

b. 不要在函数实参中创建shared_ptr

2. unique_ptr独占指针

  unique_ptr是一个独占型的智能指针,它不允许其它的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另外一个unique_ptr,unique_ptr不允许复制,但可以通过函数返回给其它的unique_ptr,还可以通过move来转移到其它的unique_ptr,这样它本身就再拥有原来指针的所有权。

注意:unique_ptr不支持make_share

3. weak_ptr弱引用指针

  弱引用指针week_ptr是用来监视shared_ptr的,不会使引用计数加1,它不管理shared_ptr内部的指针,week_ptr没有重载操作符,不共享指针,不操作资源。weak_ptr指针可以用来返回this指针和解决循环引用的问题

(1)use_count获取当前观测资源的引用计数

shared_ptr<int> p(new int(1));
weak_ptr<int> p1(p);
cout << p1.use_count() <<endl;

(2)通过expired()来判断观测的资源是否已经被释放

(3)通过lock()来获取监视的shared_ptr

(4)weak_ptr返回this指针

  不能直接将this指针返回为shared_ptr,需要通过派生std::enable_shared_from_this类,并通过其方法shared_from_this来返回智能指针,原因是enable_shared_from_this类中有一个weak_ptr指针,这个weak_ptr用来观测this智能指针,调用shared_from_this,会调用内部的weak_ptr的lock()方法

(5 )weak_ptr解决循环引用的问题

 

#include "stdio.h"
#include<memory>
#include<iostream>
using namespace std;

class B;
class A
{
public:
    shared_ptr<B> bptr;
    ~A()
    {
        cout << "A is delete!" << endl;
    }
};

class B
{
public:
    shared_ptr<A> aptr;
    ~B()
    {
        cout << "B is delete!" << endl;
    }
};
void main()
{
    {
        shared_ptr<A> a(new A());
        shared_ptr<B> b(new B());

        a->bptr = b;
        b->aptr = a;

        cout << "A的引用计数:" << a.use_count() << endl;
        cout << "B的引用计数:" << b.use_count() << endl;
    }

    int i = 0;
}

C++11智能指针

离开作用域后引用计数减1,不会去删除指针,导致内存泄漏

通过weak_ptr解决该问题,只要将A或B中的任意一个成员改成weak_ptr即可

C++11智能指针

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120118.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • flash cookie的制作和使用例子详解 三

    flash cookie的制作和使用例子详解 三前面的两篇博客介绍的是怎么用页面来操作flashcookie,还要放在容器里运行,这篇做一个简单的仅仅使用flash就可以读写flashcookie的例子先看flash中的代码,当然这次要在flash中定义一些button显示,输入等控件,看页面就知道定义了哪些控件,再看代码就知道这些控件被命名成什么[img]http://dl2.iteye.com/upload/attac…

    2022年7月15日
    16
  • LNMP状态管理命令

    LNMP状态管理命令

    2021年10月8日
    53
  • Redis事务详解

    Redis事务详解若对事务概念不清楚 请先阅读 彻底理解 MySQL 四种事务隔离级别 这篇文章 链接如下 彻底理解 MySQL 四种事务隔离级别 YaoYong BigData 的博客 CSDN 博客转入正题 结合关系型数据库的事务来看看 Redis 中事务有什么不同 Redis 事务是指将多条命令加入队列 一次批量执行多条命令 每条命令会按顺序执行 事务执行过程中不会受客户端传入的命令请求影响 Redis 事务的相关命令如下 MULTI 标识一个事务的开启 即开启事务 EXEC 执行事务中的所有命令 即提

    2025年10月14日
    2
  • 航天金税金税盘批量导入项目开发

    航天金税金税盘批量导入项目开发公司erp要实现发票导入到最新航天金税盘,数据接口文档下载地址:http://download.csdn.net/detail/y281252548/9567083不懂得联系我:免费  qq:281252548

    2022年6月4日
    58
  • CE修改器使用教程 [基础篇]

    CheatEngine一般简称CE,是一个开放源代码的作弊软件,其功能包括:内存扫描、十六进制编辑器、调试工具,CheatEngine自身附带了外挂制作工具,可以用它直接生成外挂工具,CE可以说是目前最优秀的游戏修改器不是之一,这个工具绝对值得你去学习(只要花一点时间就够了)。本篇文章只是转载内容,后期将会以一些单机游戏为重点,讲解飞天,蹲地,无敌,秒杀,等功能的实现,更多实战教程敬请…

    2022年4月3日
    653
  • phpstorm 2021.11.3 激活码(JetBrains全家桶)[通俗易懂]

    (phpstorm 2021.11.3 激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月30日
    54

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号