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

 更新时间:2023年02月02日 10:01:06   作者:Shawn-Summer  
本文主要介绍了C++11中的智能指针和垃圾回收使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在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 智能指针和垃圾回收内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Qt实现http服务的示例代码

    Qt实现http服务的示例代码

    这篇文章将为大家详细讲解有关Qt如何实现http服务,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获
    2023-04-04
  • C/C++中typedef的用法大全

    C/C++中typedef的用法大全

    typedef用法一共七种,分别是:为基本数据类型起别名、为结构体起别名、为指针类型起别名、为数组类型起别名、为枚举类型起别名、为模版函数起别名。本文就来分别讲讲这7个用法的具体实现吧
    2023-04-04
  • C语言实现2048游戏代码

    C语言实现2048游戏代码

    这篇文章主要为大家详细介绍了C语言实现2048游戏代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • C++面试八股文之如何避免死锁详解

    C++面试八股文之如何避免死锁详解

    在C++中,锁(Lock)是一种同步工具,用于保护共享资源,防止多个线程同时访问,那么如何避免死锁的情况出现呢,下面就为大家简单讲讲
    2023-07-07
  • C/C++ 监控磁盘与目录操作的示例

    C/C++ 监控磁盘与目录操作的示例

    这篇文章主要介绍了C/C++ 监控磁盘与目录操作的示例,帮助大家更好的理解和学习C/C++编程,感兴趣的朋友可以了解下
    2020-10-10
  • C++设计模式之工厂方法模式

    C++设计模式之工厂方法模式

    这篇文章主要介绍了C++设计模式之工厂方法模式,它是对简单工厂模式的扩展,,需要的朋友可以参考下
    2014-09-09
  • c++传输文件到不同计算机上的示例代码

    c++传输文件到不同计算机上的示例代码

    这篇文章主要为大家详细介绍了c++传输文件到不同计算机上的相关知识,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03
  • C++ stack用法总结(示例详解)

    C++ stack用法总结(示例详解)

    std::stack 是 C++ 标准模板库(STL)中的容器适配器,它提供了栈(stack)的功能,基于其他序列容器实现,下面给大家介绍std::stack 的用法总结,感兴趣的朋友一起看看吧
    2024-01-01
  • C++获取多浏览器上网历史记录示例代码(支持获取IE/Chrome/FireFox)

    C++获取多浏览器上网历史记录示例代码(支持获取IE/Chrome/FireFox)

    这篇文章主要介绍了C++获取多浏览器上网历史记录示例代码,支持获取IE, Chrome,FireFox等浏览器
    2013-11-11
  • C语言每日练习之冒泡排序

    C语言每日练习之冒泡排序

    这篇文章主要介绍了C语言冒泡排序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-11-11

最新评论