C++特性之智能指针shared_ptr详解

C++特性之智能指针shared_ptr详解

什么是智能指针?

智能指针是C ++中的一个重要特性,它可以避免内存泄漏和悬空指针的问题。智能指针是一个C ++类,它的析构函数自动释放分配的内存。最常见的智能指针有:

  • unique_ptr
  • shared_ptr
  • weak_ptr

其中shared_ptr是引用计数智能指针。这种智能指针在控制对象之间的共享所有权方面非常有用。它使用引用计数来跟踪有多少个指针指向同一个对象,并在不需要它时自动删除对象。

shared_ptr的使用方法

shared_ptr是一个模板类,它和unique_ptr一样,通常使用std命名空间。我们来看一下shared_ptr的使用方法。

向shared_ptr分配内存的方式有两种,一种是通过new运算符直接进行内存分配,另一种是通过std::make_shared函数进行分配。

通过new运算符分配内存的方式

std::shared_ptr<int> p1(new int(10));
std::shared_ptr<std::string> p2(new std::string("hello shared_ptr"));

在上述例子中,我们使用了new运算符来分配内存,并将其传递给shared_ptr构造函数。通过new运算符分配内存的方式需要显式释放内存,不然会导致内存泄漏。当使用shared_ptr管理指针时,不需要显示调用delete函数释放内存。

通过std::make_shared函数分配内存的方式

auto p3 = std::make_shared<int>(10);
auto p4 = std::make_shared<std::string>("hello shared_ptr");

使用std::make_shared函数可以更加方便的分配内存,这种方式不需要显式的释放内存,因为智能指针会自动进行管理,并在对象不再被使用时释放对象所占用的内存。

shared_ptr的拷贝和移动

shared_ptr是一个指向对象的指针,多个shared_ptr可以指向同一个对象。每个shared_ptr都有一个引用计数器,当有一个新的shared_ptr指向该对象时,计数器值加一。当任意一个shared_ptr生命周期结束时,计数器值减一。只有当计数器值为零时,才会释放对象的内存。

下面我们看一个简单的例子.

#include <iostream>
#include <memory>

int main() {
    auto p1 = std::make_shared<int>(10);
    std::cout << "p1 count:" << p1.use_count() << std::endl;
    {
        auto p2 = p1;
        std::cout << "p1 count:" << p1.use_count() << std::endl;
        std::cout << "p2 count:" << p2.use_count() << std::endl;
    }
    std::cout << "p1 count:" << p1.use_count() << std::endl;
    return 0;
}

输出结果如下所示:

p1 count:1
p1 count:2
p2 count:2
p1 count:1

该程序分别创建了两个shared_ptr,p1和p2,它们都指向同一个整型对象。在创建p2时,p2指向p1所指向的对象,并且两者拥有相同的计数器。当内部作用域结束时,p2被销毁并计数器减一,但p1仍然存在,因此p1的计数器不为零。在程序结束时,p1销毁并计数器减一,因此计数器为零,整型对象被销毁。

shared_ptr可以通过拷贝和移动进行赋值,下面我们来看一下拷贝和移动的用法。

#include <iostream>
#include <memory>

int main() {
    auto p1 = std::make_shared<int>(10);
    std::cout << "p1 count:" << p1.use_count() << std::endl;
    auto p2(p1);
    std::cout << "p1 count:" << p1.use_count() << std::endl;
    std::cout << "p2 count:" << p2.use_count() << std::endl;
    auto p3 = std::move(p1);
    std::cout << "p1 count:" << p1.use_count() << std::endl;
    std::cout << "p3 count:" << p3.use_count() << std::endl;
    return 0;
}

输出结果如下所示:

p1 count:1
p1 count:2
p2 count:2
p1 count:0
p3 count:2

在上面的例子中,首先创建共享指针p1并将其数量计为1。然后通过拷贝构造函数创建了两个新的共享指针p2和p1,并将其数值增加至2。接下来,使用std::move操作将p1的所有权转移给p3,并使p1指向null。此时,p3和p2计数器的值都为2,而p1指向null。

shared_ptr的示例说明

下面是一个使用shared_ptr管理动态数组的示例:

#include <iostream>
#include <memory>

int main() {
    auto p1 = std::make_shared<int[]>(3);
    p1[0] = 10;
    p1[1] = 20;
    p1[2] = 30;
    for (int i = 0; i < 3; i++) {
        std::cout << "p1[" << i << "]=" << p1[i] << std::endl;
    }
    return 0;
}

上面的代码创建了一个动态数组,并使用shared_ptr管理动态数组的内存。我们可以像使用原生数组一样来操作p1,包括访问元素和遍历。当程序结束时,p1所占用的内存会自动释放。

下面是一个示例,使用shared_ptr构建一个类的实例。

#include <iostream>
#include <memory>

class A {
public:
    A(int a) : a(a) {}

    void print() {
        std::cout << "a=" << a << std::endl;
    }

private:
    int a;
};

int main() {
    auto p1 = std::make_shared<A>(10);
    p1->print();
    return 0;
}

上面的代码创建了一个类A的实例,并使用shared_ptr管理对象的内存。我们可以像使用原生指针一样来操作p1,包括调用成员函数和访问成员变量。当程序结束时,p1所占用的内存会自动释放。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++特性之智能指针shared_ptr详解 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • 布隆过滤器(bloom filter)及php和redis实现布隆过滤器的方法

    布隆过滤器及实现方法攻略 什么是布隆过滤器? 布隆过滤器是一种非常实用的数据结构,它可以用于快速判断一个元素是否在一个集合中。布隆过滤器可以有效地降低查询一个元素是否在集合中的时间复杂度,但是会带来一定的误判率。它由早在1970年提出,以其高效的查询速度和内存占用率低的特点而广受欢迎,被广泛应用于网络爬虫等场景中。 布隆过滤器的实现原理 布隆过滤器采用的是概…

    C 2023年5月22日
    00
  • c++ 中__declspec 的用法详解

    下面是对 __declspec 在 C++ 中的详细讲解: 1. __declspec 的定义 __declspec 是 MicroSoft 编译器用来扩展代码基本属性的关键字,用于声明一个特殊的属性。通过使用 __declspec,开发者可以控制导出和从 DLL 中导入函数或数据,以及控制函数的调用约定、内联性、对齐性等属性。 2. __declspec …

    C 2023年5月23日
    00
  • C语言将音视频时钟同步封装成通用模块的方法

    在C语言中将音视频时钟同步封装成通用模块主要可以分为以下几个步骤: 1. 定义时钟同步结构体 使用结构体保存相关的时钟同步数据,如音视频播放起始时间、时钟周期、当前时钟时间等信息,方便后续模块进行时钟同步计算和状态管理。 typedef struct { int64_t start_pts; // 音视频播放起始时间,单位:微秒 int64_t num; /…

    C 2023年5月23日
    00
  • C++实现完整功能的通讯录管理系统详解

    C++实现完整功能的通讯录管理系统详解 本文将详细讲解如何使用C++语言实现一个完整功能的通讯录管理系统,包含联系人的增、删、改、查等基础功能,以及文件读写、界面美化等高级功能,以及如何使用编程技巧提高代码的可读性和可维护性。 程序的需求分析 管理员:管理员需要进行登录和注销操作,并对通讯录进行增、删、改、查等管理操作; 通讯录:通讯录需要记录联系人的姓名、…

    C 2023年5月23日
    00
  • NodeJs基本语法和类型

    Node.js是一种运行在服务器端的JavaScript,可以用于构建高效的事件驱动应用程序。在使用Node.js时,掌握其基本语法和类型非常重要。 基本语法 注释 JavaScript中的注释分为两种:单行注释和多行注释。单行注释用//表示,多行注释用/…/表示。 // 这是单行注释 /* 这是 多行 注释 */ 变量 使用var、let、const声…

    C 2023年5月23日
    00
  • C币交易所是怎么交易数字货币的?C币交易所支持哪些数字货币交易?

    C币交易所是一个数字货币交易平台,支持用户交易多种数字货币。在 C币交易所进行数字货币交易,需要注册一个账户,然后在账户中充值一定数量的数字资产,再根据当前市场价格进行买卖交易。 以下是数字货币交易的具体流程: 1. 注册账户 在C币交易所的官网上点击注册按钮,填写必要的个人信息完成注册并激活账户后,即可开始数字货币交易。 2. 充值数字资产 在C币交易所首…

    C 2023年5月23日
    00
  • C语言 将数组传递给函数

    将数组传递给函数在C语言中是一种常见的操作,这种操作可以让我们更加方便地管理和操作数组数据。下面详细讲解如何将数组传递给函数。 函数原型 在C语言中,我们在函数中使用数组参数时,必须在函数原型中声明该参数的类型和名称,例如: void function_name(int array[], int size); 这里,array[]表示该参数是一个数组,int…

    C 2023年5月9日
    00
  • C语言回溯法 实现组合数 从N个数中选择M个数

    下面是C语言回溯法实现组合数从N个数中选择M个数的完整攻略: 核心思路 回溯法是一种经典的问题求解方法,其基本思路是:从一条路径开始,依次尝试每一个分支,递归地进行尝试,直到找到解为止,而如果该路径无解,则回退到上一个路径,继续尝试其他分支。 在利用回溯法解决从N个数中选择M个数的组合数问题时,我们可以将每个数看作一个节点,根据回溯的思想依次尝试每一个节点,…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部