P30 C++智能指针

2023-12-13 13:23:55

前言

🎬 个人主页:@ChenPi

🐻推荐专栏1: 《C++_@ChenPi的博客-CSDN博客》????

🔥 推荐专栏2: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》???

🛸推荐专栏3: ??????《 链表_@ChenPi的博客-CSDN博客 》 ???
🌺本篇简介 ?: ?这章我们将学习一下C++的智能指针

仔细算了一下,好像也好多天没有更新C++系列了,因为最近在嵌入式的项目,然后老出Bug,就很烦,就来学点C++来散下心

大概就是操作界面加摄像头做识别,加网络控制,还有温湿度曲线图,这是还没搞好,搞好了在考虑做个专栏了?

我们回归主题,这章我们学C++的智能指针,学习智能指针之前,我们先要了解一下什么是指针

本期的主题是 C++ 中的智能指针。

P7 C++指针-CSDN博客

在这里,我们将讨论什么是智能指针以及它能为你做什么。

在之前的内容中,我们讨论了 new、delete 这些内容。

new 是在堆上分配内存,需要 delete 来释放内存,

因为它不会自动的释放内存。

智能指针是实现这一过程自动化的一种方式。

当使用智能指针时,你可以不用调用 delete,

在很多情况下,甚至不需要调用 new。

很多人都倾向于使用不调用 new 或 delete 的这种 C++ 编程风格,

智能指针是实现这个的一种方法。

01?unique_ptr作用域指针

智能指针本质上是一个原始指针的包装,

当你创建一个智能指针,它会调用 new 并为你分配内存,然后基于你使用的智能指针,这些内存会在某一时刻自动释放。

让我们来看看第一个,也是最简单的智能指针 unique_ptr。

unique_ptr 是作用域指针,超出作用域时,它会被销毁。

当你想要一个作用域内使用的指针的时候,

unique_ptr 是很的参考。

让我们来看一个例子。

使用智能指针的第一步要先包含 memory 头文件。

现在我们有了 Entity 类,它有构造函数和析构函数

会在调用时打印相应的信息

这样我们就能了解这些智能指针的行为。

1.1 unique_pt实例化对象

在主函数中,我们在一个空作用域下使用 unique_ptr 来分配一个 Entity。

使用的方法就是如上所示。

这里有个需要注意的点就是, unique_ptr 的构造函数是 explicit 的

没有隐式转换功能, 需要显式的调用构造函数,

这就是使用 unique_ptr 的一种方式,

所以你不能这样写 std::unique_ptr entity()= new Entity()。

然后你就可以像普通的指针一样使用 entity 了。

还有一种方法就是

当然更好的方法是先使用 std::make_unique,再赋值给 unique_ptr。

    std::unique_ptr<Entity>entity2 = std::make_unique<Entity>();

这对于 unique_ptr 很重要,主要原因是出于异常安全

因为如果构造函数碰巧抛出异常,它会稍微安全一点

你不会得到一个没有引用的悬空指针,从而造成内存泄漏

这个之后的系列会介绍。

上面的程序调试后就会有这样的效果,申请的这段内存在作用域结束的时候被释放了。

这就是最简单的智能指针了,非常有用,开销很低,它甚至没有开销,

它只是一个栈分配对象,当栈分配对象死亡时,它将调用 delete,释放内存。

1.2 unique_ptr智能指针的小细节

现在出现一个问题,正如上面提到的,如果你想复制这个指针,

使得这个指针可以被传递到一个函数或者另一个类中,然而你却不能复制它。

02?shared_ptr共享指针

如果你真有这样的需求,那么可以使用共享指针 shared_ptr

shared_ptr 有点不同,它还在底层做了很多其它的事情

shared_ptr 实现的方式实际上取决于编译器和你在编译器中使用的标准库

目前来看,它使用的主要是引用计数

引用计数基本上是一种方法,可以跟踪你的指针有多少个引用,

一旦引用计数达到零,它就被删除了。

举个例子,我创建了一个共享指针 shared_ptr,然后创建了另一个 shared_ptr 来复制它,我的引用计数是2(第一个和第二个,共两个),当第一个挂掉的时候,引用计数器就会减少1。当最后一个挂掉的时候,引用计数回到零,内存被释放。

使用共享指针 shared_ptr的方法很简单,如下举例。

shared_ptr 有点不一样的地方在于,它需要分配另一块内存,叫做控制块,

用来存储引用计数,所以如果你首先创建一个 new Entity,

然后将其传递给 shared_ptr 构造函数,它必须分配,

做2次内存分配(先做一次 new Entity 的分配,然后是 shared_ptr 控制内存块的分配)。

如果你用 make_shared,你能把它们组合起来,这样更有效率。

你不妨按照下面的例子做一个简单的测试,提前想一下调试过程,运行看看是否和你想得一样。

可以看到构造函数已经被创建了

因为构造函数里面的cout已经被打印了

然后当计数为0的时候,它将调用 delete,释放内存

这些都是非常好的工具,你可以经常使用它们,它们可以让你的代码自动化,防止你因为忘记调用 delete 而造成内存泄漏。

shared_ptr 是有一点额外的开销的,因为它的引用计数系统。但是话又说回来,很多倾向于编写自己的内存管理系统的人,也一样会有一些开销。

如果决定了要使用智能指针,建议你优先使用 unique_ptr,然后是 shared_ptr,这才是正确的方式。

测试代码

#include <iostream>
#include <memory>

class Entity
{
private:

public:
    Entity()
    {
        std::cout<<"Entity Created"<<std::endl;
    }
    ~Entity()
    {
        std::cout<<"Entity Destroyed"<<std::endl;
    }
};

int main()
{

{
    std::shared_ptr<Entity> entity;
    {
        std::shared_ptr<Entity> shared_Entity = std::make_unique<Entity>();
        entity = shared_Entity;
    }
}

    return 0;
}

文章来源:https://blog.csdn.net/weixin_73901182/article/details/134863411
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。