首页 > 编程语言 >C++速览之智能指针

C++速览之智能指针

时间:2024-08-16 15:56:45浏览次数:15  
标签:cout int C++ 内存 速览 shared ptr 指针

1、存在的问题
c++ 把内存的控制权对程序员开放,让程序显式的控制内存,这样能够快速的定位到占用的内存,完成释放的工作。但是此举经常会引发一些问题,比如忘记释放内存。由于内存没有得到及时的回收、重复利用,所以在一些c++程序中,常会遇到程序突然退出、占用内存越来越多,最后不得不选择重启来恢复。造成这些现象的原因可以归纳为下面几种情况.

1.1 野指针
出现野指针的有几个地方 :
指针声明而未初始化,此时指针的将会随机指向
内存已经被释放、但指针仍然指向它。这时内存有可能被系统重新分配给程序使用,从而会导致无法估计的错误;

#include <iostream>

using namespace std;

int mian(){
    //1. 声明未初始化
    int *p1 ;
    cout << "打印p1: " << *p1 << endl;
    
    
    //2. 内存释放后,并没有置空 nullptr
    int *p = new int(55);

    cout << "释放前打印 :  " << *p << endl;

    delete  p ;
    cout << "释放后打印 :  " << *p << endl;
    
    return 0 ;
}

1.2 重复释放
程序试图释放已经释放过的内存,或者释放已经被重新分配过的内存,就会导致重复释放错误.

int main(){

    int *p = new int(4);

    //重复释放
    delete p;
    delete p;

    return 0 ;
}

1.3 内存泄漏
不再使用的内存,并没有释放,或者忘记释放,导致内存没有得到回收利用。 忘记调用delete

int main(){

    int *p = new int(4);
    
    
    //后面忘记调用delete p;

    return 0 ;
}

2、智能指针
为了解决普通指针的隐患问题,c++在98版本开始追加了智能指针的概念,并在后续的11版本中得到了提升
c++11标准用 unique_ptr | shared_ptr | weak_ptr 等指针来自动回收堆中分配的内存。智能指针的用法和原始指针用法一样,只是它多了些释放回收的机制罢了。

2.1 unique_ptr
unique_ptr 是一个独享所有权的智能指针,它提供了严格意义上的所有权
也就是只有这个指针能够访问这片空间,不允许拷贝,但是允许移动(转让所有权)

#include<iostream>
#include <memory>

using namespace std;

int main() {


    // 1. 创建unique_ptr对象,包装一个int类型指针
    unique_ptr<int> p(new int(10));

    // 2. 无法进行拷贝。编译错误
    //unique_ptr<int> p2 = p;
    cout << "-----1----" << *p << endl;

    // 3. 可以移动指针到p3. 则p不再拥有指针的控制权 p3 现在是唯一指针
    unique_ptr<int> p3 = move(p);
    cout << "-----2----" << *p3 << endl;

    // p 现在已经无法取值了。
    // cout << "-----3----" << *p << endl;

    // 可以使用reset显式释放内存。
    p3.reset();

    // 重新绑定新的指针
    p3.reset(new int(6));

    // 获取到包装的int类型指针
    int *p4 = p3.get();

    // 输出6
    cout << "-----4----" << "指针指向的值是:" << *p4 << endl;
    cout << "-----5----" << "*p3值是:" << *p3 << endl;

    return 0;
}

2.2 shared_ptr
shared_ptr : 允许多个智能指针共享同一块内存,由于并不是唯一指针,所以为了保证最后的释放回收,采用了计数处理,每一次的指向计数 + 1 , 每一次的reset会导致计数 -1 ,直到最终为0 ,内存才会最终被释放掉。 可以使用use_cout 来查看目前的指针个数

#include <iostream>
#include <memory>

using namespace std;

class Stu {
public:
    Stu() {
        cout << "执行构造函数" << endl;
    }

    ~Stu() {
        cout << "执行析构函数" << endl;
    }
};

int main() {
    shared_ptr<Stu> s1(new Stu());
    cout << " ---1--- = " << s1.use_count() << endl;  // 查看指向计数
    shared_ptr<Stu> s2 = s1;
    cout << " ---2--- = " << s1.use_count() << endl;  // 查看指向计数
    shared_ptr<Stu> s3 = s1;
    cout << " ---3--- = " << s1.use_count() << endl;  // 查看指向计数
    s1.reset();
    cout << " ---4--- = " << s3.use_count() << endl;  // 查看指向计数
    s2.reset();
    cout << " ---5--- = " << s3.use_count() << endl;  // 查看指向计数
    s3.reset();  // 至此全部解除指向 计数为0 。 会执行stu的析构函数
    cout << " ---6--- = " << s3.use_count() << endl;  // 查看指向计数

    return 0;
}

在这里插入图片描述
问题
对于引用计数法实现的计数,总是避免不了循环引用(或环形引用)的问题,即我中有你,你中有我,shared_ptr也不例外。 下面的例子就是,这是因为f和s内部的智能指针互相指向了对方,导致自己的引用计数一直为1,所以没有进行析构,这就造成了内存泄漏

#include <iostream>
#include <memory>

using namespace std;

class Son;

class Father {
private:
    shared_ptr<Son> son;
public:
    Father() {
        cout << "father 构造" << endl;
    }

    ~Father() {
        cout << "father 析构" << endl;
    }

    void setSon(shared_ptr<Son> son) {
        this->son = son;
    }
};

class Son {
private:
    shared_ptr<Father> father;
public:
    Son() {
        cout << "son 构造" << endl;
    }

    ~Son() {
        cout << "son 析构" << endl;
    }

    void setFather(shared_ptr<Father> father) {
        this->father = father;
    }
};


int main() {
    shared_ptr<Father> f(new Father());
    shared_ptr<Son> s(new Son());
    f->setSon(s);
    s->setFather(f);
}

在这里插入图片描述
解决办法
定义对象的时候,用shared_ptr指针;引用对象的地方,用weak_ptr指针

2.3 weak_ptr

#include <iostream>
#include <memory>

using namespace std;

class Son;

class Father {
private:
    weak_ptr<Son> son;
public:
    Father() {
        cout << "father 构造" << endl;
    }

    ~Father() {
        cout << "father 析构" << endl;
    }

    void setSon(shared_ptr<Son> son) {
        this->son = son;
    }
};

class Son {
private:
    weak_ptr<Father> father;
public:
    Son() {
        cout << "son 构造" << endl;
    }

    ~Son() {
        cout << "son 析构" << endl;
    }

    void setFather(shared_ptr<Father> father) {
        this->father = father;
    }
};


int main() {
    shared_ptr<Father> f(new Father());
    shared_ptr<Son> s(new Son());
    f->setSon(s);
    s->setFather(f);
}

在这里插入图片描述

标签:cout,int,C++,内存,速览,shared,ptr,指针
From: https://blog.csdn.net/qq_44114055/article/details/141106837

相关文章

  • 指针学习(3)
     目录1.字符指针变量​编辑2.数组指针变量2.1定义2.2存放3.二维数组传参的本质4.函数指针变量4.1创建4.2使用 ​编辑5.typedef关键字6.函数指针数组6.1转移表1.字符指针变量顾名思义,字符指针也就是char*,在使用中,一般简单的使用可以这样#include<stdio.h>i......
  • C++ Debug
    如果右上角没有runanddebugbutton记得把setting里IntelliSenseEngine改成default,以及DebugShortcut打开如果cpp文件提示headernotfound,那需要在c_cpp_properties.json中把compilerPath,添加上debug的时候,默认他好像是会自动build的,当然也可以自己写p......
  • C++构造和析构
    文章目录一、构造函数1、构造函数的功能2、构造函数的创建3、默认构造函数二、析构函数1、析构函数的功能2、析构函数的的创建三、拷贝构造函数1、拷贝构造的功能2、拷贝构造的创建3、深拷贝一、构造函数1、构造函数的功能构造函数是一个类的成员函数,在类创......
  • C++图像识别、图像识别接口、ocr api
    如果您在找工作并且在找内容审核编辑的工作,那么不难发现,快手在全国多个招聘网站发布了关于“内容审核编辑”岗位的招聘信息,据悉,此次的“内容审核编辑”岗位招聘的规模达3000人。因为快手上面“低龄妈妈”内容的炒作,所以被要求整改,才有后续的大规模招聘内容审核编辑人员的现象......
  • 【C++的剃刀】我不允许你还不会map和set
     ​ 学习编程就得循环渐进,扎实基础,勿在浮沙筑高台   循环渐进Forward-CSDN博客Hello,这里是kiki,今天继续更新C++部分,我们继续来扩充我们的知识面,我希望能努力把抽象繁多的知识讲的生动又通俗易懂,今天要讲的是C++的map和set~目录 循环渐进Forward-CSDN博客关......
  • C/C++算法概述
    摘要1.性能优势:C/C++语言以其接近硬件的特性而著称,提供了对底层硬件的直接控制能力。这意味着算法可以实现更高的执行效率,特别是在需要处理大量数据或实时性能要求较高的场景中。2.灵活性:C/C++提供了丰富的数据结构和操作,允许开发者以灵活的方式实现复杂的算法。同时,C++的......
  • 红温刷算法题(C/C++)
    此文章主要是给刷算法题的小萌新写的题解,博主每日刷题,把所刷的题以及所获都会发到博客里面,文章有详解思路,并且有对应的AC代码,希望我的博客对算法小萌新有所帮助。感谢CSDN平台给我这个机会,我会努力创作,创作高质量文章。 P1002[NOIP2002普及组]过河卒题目描述棋盘上 A ......
  • C++基础资料二
    C++等级考试资料二考试内容:选择题:进制转换、冒泡与选择排序、二分思想、链表与顺序表、二维数组初始化、函数阅读编程题:字符串操作、质数判断、排序、最小公倍数、最大公约数、百钱百鸡问题 考试资料:进制转换公式1.十进制转二进制整数部分:不断将十进制数除以2,记录余......
  • C++中的IO流
    目录1.C语言的输入与输出2.流是什么3.C++IO流标准IO流IO流的四个标志C++文件IO流4.stringstream的简单介绍1.C语言的输入与输出C语言中我们用到的最频繁的输入输出方式就是scanf()与printf()。scanf():从标准输入设备(键盘)读取数据,并将值存放在变量中。printf(......
  • C++之内存四区
    目录一、内存四区二、程序运行前三、程序运行后四、new操作符一、内存四区在计算机科学中,特别是在c或c++语言编程时,内存通常大致分为四个区域,而不同的区域存放的数据赋予不同的生命周期,给我们更大的灵活编程:代码区:存储程序的可执行代码(二进制代码),也就是程序编译后的......