文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++11中的智能指针和垃圾回收使用

2023-02-02 12:02

关注

在C/C++中,我们需要自己管理动态内存区,我们在写代码中可能会出现如下3中内存管理的缺陷

C++恶心的地方就在于它存在指针,需要编写者自己管理内存,所以内存上面的问题就会有很多,但是在其他语言,例如python,java,C#,他都不存在指针概念,也就意味著你不需要开辟释放内存这些操作。而正因为C++将指针暴露出来,甚至将右值引用暴露出来,才使得C++的运行效率非常快。

为了减少C++中的内存问题,就出现了智能指针,它是一种对C风格指针的优化,它把内存的释放放在了智能指针的析构函数中,这样子就能减少一部分自己手动释放内存的代码。

1.C++11中的unique_ptr

#include<memory>
#include<iostream>
using namespace std;
int main()
{
    unique_ptr<int> up1(new int(11));
    unique_ptr<int> up2=up1;//无法通过编译

    cout<<*up1<<endl;//11
    unique_ptr<int> up3=move(up1);//现在up3是数据的唯一指针

    cout<<*up3<<endl;//11
    cout<<*up1<<endl;//运行错误

    up3.reset();//释放内存
    up1.reset();//不会重复释放内存

    cout<<*up3<<endl;//运行错误
}

我们知道unique_ptr正如它的名字一样,它表示一个对象只能由一个指针绑定,不允许一个对象同时又多个unique_ptr绑定。

而且 unique_ptr只存在移动语义,而不存在拷贝语义 ,我们看上面代码中unique_ptr<int> up3=move(up1);,在unique_ptr中只存在移动构造函数和移动赋值函数,不存在拷贝构造函数和拷贝赋值函数。所以说我们只能用右值来构造或赋值unique_ptr。

还有一种初始化unique_ptr的方法就是:make_unique<>(),相较于使用new初始化,前者内存碎片化更少,在现代C++种主要使用,make_unique。

实际上,C++98中的auto_ptr和C++11中的unique_ptr实现的是同一个东西,但是在C++98中我们不存在移动语义,所以auto_ptr它是存在拷贝构造函数和拷贝赋值函数的,所以诸如:
auto_ptr<int> up2=up1;是可以通过编译的,在C++11中我们废弃掉了,auto_ptr也是这个原因。

2.C++11中的shared_ptr和weak_ptr

shared_ptr是一种共享式的指针,它采用引用计数的方式,来决定何时释放内存,引用计数就是说,它统计每个对象有几个指针指向它。一旦一个对象的引用计数为0,即不存在指向它的指针,那么就释放它。
weak_ptr是用来验证shared_ptr指向的内存单元的有效性的,被它指向的对象的引用计数不会增加。

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

void Check(weak_ptr<int>& wp)
{
    shared_ptr<int> sp=wp.lock();
    if(sp!=nullptr)
        cout<<"still "<<*sp<<endl;
    else
        cout<<"pointer is invalid."<<endl;
}
int main()
{
    shared_ptr<int> sp1=make_shared<int>(22);
    shared_ptr<int> sp2=sp1;
    weak_ptr<int> wp=sp1;

    cout<<*sp1<<endl;
    cout<<*sp2<<endl;
    Check(wp);

    sp1.reset();
    cout<<*sp2<<endl;
    Check(wp);

    sp2.reset();
    Check(wp);

}

22
22
still 22
22
still 22
pointer is invalid.

3.垃圾回收

虽然智能指针能够帮助用户有效管理堆内存,但是它还是需要显式声明智能指针,而完全不需要指针的内存管理方法也会更讨人喜欢。这种方法就是垃圾回收机制,写代码的时候不需要开辟释放内存操作,这些操作都由编译器自动实现,这种智能化的方案就是垃圾回收机制。

遗憾的是,C++不支持垃圾回收机制。

垃圾回收的方式有4种

基于引用计数的方法
其实就是和shared_ptr一样的方式,就是一旦对象的引用次数为0就释放它,python就是使用的这种方案,不过这种方案不好,它效率比较低,一旦对象创建,或者有指针指向它,都要计算引用此时,而且它不能解决"环形引用"问题

标记-清除
这种方法就是存在一个根对象,它管理所有对象,依次遍历每个对象,给它们引用的区域打上标记,然后遍历完成后,把所有没有标记的区域释放掉,这种方案的缺陷在于会存在大量的内存碎片

标记-整理
它是在标记-清除方案的基础上,标记完后不再遍历释放垃圾了,而是所有被标记的区域,向左靠齐,这样就减少了内存碎片

标记-拷贝
它是将内存空间分为两块:From和to,刚开始就从From空间种分配内存,一旦From内存满了,就把From空间中所有活对象,拷贝到to空间中,而且都是向左靠齐的,然后再将From和to的角色互换。

很遗憾C++11目前还没有公开支持过垃圾回收,不过有些库和有限编译器支持了部分垃圾回收的功能

int main()
{
    int *p=new int;
    p+=10;
    p-=10;
    *p=10;
}

上面代码中,一旦p指向了其他区域,如果你的编译器支持垃圾回收,例如采用的引用计时方式,那么一旦p移到了其他地区,这个开辟的new int空间,就会被释放,更危险的是,这块空间会被其他线程使用,这时候,p如果又指回了原来的地方,那么p就是一个野指针。

为了防止,new int这块空间被垃圾回收器回收掉,我们的一种方案是:

int main()
{
    int *p=new int;
    declare_reachable(p);
    p+=10;
    p-=10;
    *p=10;
}

这里的declare_reachable函数显式的告诉垃圾回收器,你不要取释放这块空间

到此这篇关于C++11中的智能指针和垃圾回收使用的文章就介绍到这了,更多相关C++11 智能指针和垃圾回收内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯