C++超详细讲解智能指针

C++超详细讲解智能指针

简介

在C++中,智能指针是一种非常有用、安全的内存管理工具。相较于原始指针,它能够自动释放内存,避免内存泄漏等问题。同时,智能指针也能够避免重复释放内存、访问空指针以及释放栈上分配的内存等问题。本文将对智能指针进行详细的讲解,介绍其类型、使用方法以及注意事项。

智能指针类型

在C++中,常见的智能指针有以下几种:

unique_ptr

unique_ptr是C++11引入的一种独占式智能指针。它能够自动管理动态分配的内存,并在不需要时自动释放。

示例:

#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> p(new int(42));
    std::cout << *p << std::endl;
    return 0;
}

在以上示例中,定义了一个unique_ptr指针p,并通过new运算符分配了一个整型变量的内存空间,该指针p独占该内存空间,当p超出作用域时,该内存空间会自动被释放。

shared_ptr

shared_ptr是一种共享式智能指针,它允许多个智能指针同时指向同一个对象,并会自动释放对象的内存空间,当最后一个指向该对象的智能指针被销毁时。

示例:

#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> p1(new int(42));
    std::shared_ptr<int> p2 = p1;
    std::cout << *p1 << std::endl;
    std::cout << *p2 << std::endl;
    return 0;
}

在以上示例中,定义了两个shared_ptr指针,通过将p1赋值给p2,两个指针共享同一个对象的内存空间,当p1和p2超出作用域时,该内存空间会自动被释放。

weak_ptr

weak_ptr是一种弱引用智能指针,它指向一个shared_ptr所管理的对象,但它并不对所指的对象进行引用计数,而只是提供了一个观察的手段。当最后一个shared_ptr被销毁时,weak_ptr自动失效。

示例:

#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> p1(new int(42));
    std::weak_ptr<int> p2 = p1;
    std::cout << *p1 << std::endl;
    // std::cout << *p2 << std::endl; // weak_ptr不能直接使用,需要先判断是否过期
    if (auto p3 = p2.lock()) {
        std::cout << *p3 << std::endl;
    }
    return 0;
}

在以上示例中,定义了一个shared_ptr指针p1和一个weak_ptr指针p2,通过将p1赋值给p2,p2指向p1所管理的对象,在输出p1的值之后,使用weak_ptr的lock()方法获取p2指向的对象,并输出该对象的值。

智能指针使用方法

定义智能指针

定义智能指针可以使用STL中的模板类unique_ptr、shared_ptr和weak_ptr,以及boost库中的intrusive_ptr、scoped_ptr等。

#include <memory>
#include <boost/scoped_ptr.hpp>

int main(){
    std::shared_ptr<int> p1(new int(1));
    std::unique_ptr<int> p2(new int(2));
    boost::scoped_ptr<int> p3(new int(3));
    return 0;
}

释放内存空间

不需要手动释放。当智能指针超出其作用域后,其指向的内存空间会自动被回收。

获取指针的指向

对于unique_ptr和shared_ptr,可以使用get()方法获取底层的原始指针;对于weak_ptr,需要使用其lock()方法获取底层的shared_ptr指针,然后再使用get()方法获取底层的原始指针。

#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> p1(new int(1));
    std::shared_ptr<int> p2(new int(2));
    std::weak_ptr<int> p3 = p2;
    std::cout << p1.get() << std::endl; // 输出p1指向的原始指针地址
    std::cout << p2.get() << std::endl; // 输出p2指向的原始指针地址
    std::cout << p3.lock().get() << std::endl; // 输出p3指向的原始指针地址
    return 0;
}

其他操作

可以通过reset()方法将智能指针重置为nullptr;使用operator bool()方法检查智能指针是否为空指针。

#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> p1(new int(1));
    std::shared_ptr<int> p2(new int(2));
    p1.reset(); // 释放p1
    p2.reset(); // 释放p2
    std::cout << p1 << std::endl; // 输出nullptr
    std::cout << p2 << std::endl; // 输出nullptr
    if (!p1) {
        std::cout << "p1 is null" << std::endl; //输出p1为空指针
    }
    if (!p2) {
        std::cout << "p2 is null" << std::endl; //输出p2为空指针
    }
    return 0;
}

注意事项

避免循环引用

当两个对象互相引用时,可能会导致内存泄漏。比如,一个对象A持有另一个对象B的shared_ptr,而B对象也持有A对象的shared_ptr。这种情况下,两个A、B对象的引用计数永远不会变为0,导致泄漏内存。

要避免这种循环引用,可以使用weak_ptr。一般情况下,A对象持有B对象的shared_ptr,而B对象持有A对象的weak_ptr。

不允许栈上分配

由于智能指针的析构函数是自动释放分配的堆栈内存,因此不允许在栈上分配智能指针。

std::unique_ptr<MyClass> p(new MyClass); // 正确写法
std::unique_ptr<MyClass> p2 = std::make_unique<MyClass>(); // C++14后的写法
std::unique_ptr<MyClass> p3(&myclass); // 错误写法,不能在栈上分配

总结

本文对C++中的智能指针进行了介绍,包括其类型、使用方法以及注意事项。智能指针是一种非常有用、安全的内存管理工具,使用智能指针可以避免很多内存管理问题。

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

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

相关文章

  • 前端常见跨域解决方案(全)

    前端常见跨域解决方案,主要是因为浏览器同源策略(Same Origin Policy)的限制,导致一个域名下的前端代码无法直接请求另一个域名的资源,这就是所谓的“跨域”。 下面介绍几种前端常见的跨域解决方案。 1. JSONP JSONP 是前端跨域解决方案中最简单、最常用的一种。它通过动态创建 <script> 标签,再请求一个带有回调函数的接…

    C 2023年5月23日
    00
  • 天天飞车C级赛车威酷属性解析 天天飞车威酷怎么样

    天天飞车C级赛车威酷属性解析 背景介绍 天天飞车是一款流行的赛车竞速游戏,近年来越来越受欢迎。C级赛车威酷作为其中的一种赛车,有着很好的属性表现。本文将详细讲解C级赛车威酷的属性和使用技巧,帮助玩家更好地体验游戏。 属性解析 速度 C级赛车威酷的速度属性为50,算不上顶尖,但也不差。玩家在使用该车时应该注重提高赛车的加速度,以把车开到最高速度。 操控 C级赛…

    C 2023年5月23日
    00
  • C++实现管理系统的示例代码

    C++实现管理系统的示例代码包含以下步骤: 设计系统需求和功能 在开始写代码之前需要明确系统的需求和功能,这可以帮助我们更好地组织代码。例如,我们可以列出以下需求和功能: 系统应该能够添加、查看、修改和删除学生信息 学生信息应该包括姓名、年龄、性别等基本信息 系统应该能够按姓名、年龄、性别等信息对学生信息进行排序 系统应该能够将学生信息保存到文件中,并能够从…

    C 2023年5月23日
    00
  • C语言中的sscanf()函数使用详解

    C语言中的sscanf()函数使用详解 简介 sscanf() 是 C 语言中用于格式化输入的函数,它可以解析字符串,将指定格式的数据转换成相应的类型,并存储到对应的变量中。 sscanf() 函数工作方式类似于 scanf() 函数,唯一的区别是前者从指定字符串中读取参数,而后者则是从标准输入中读取参数。 函数原型 函数原型如下: int sscanf(c…

    C 2023年5月22日
    00
  • C语言const关键字的用法详解

    C语言const关键字的用法详解 1. 简介 在C语言中,const关键字通常被用来声明常量,即在程序运行过程中不会被修改的值。在声明变量或函数时使用const关键字可以增加程序的可读性和可维护性。 2. 声明常量 要声明一个常量,需要在变量声明时加上const关键字。例如: const int MAX_VALUE = 100; 在这个声明中,MAX_VAL…

    C 2023年5月23日
    00
  • C/C++ Qt 数据库与Chart历史数据展示

    C/C++ Qt 数据库与Chart历史数据展示攻略 介绍 Qt 是一款跨平台的GUI应用开发框架,它有很多成熟的库和工具,同时也提供了对数据库和数据可视化的支持。这里将介绍如何使用 C++ Qt 开发一个历史数据展示的程序。主要涉及到以下三个方面: 数据库连接与操作 数据可视化 (Chart) 图形界面设计 (UI) 在程序中,我们会使用 MySQL 作为…

    C 2023年5月22日
    00
  • VS2022实现VC++打包生成安装文件图文详细历程

    下面将为你详细讲解“VS2022实现VC++打包生成安装文件图文详细历程”,主要步骤包括创建VC++工程、打包生成、安装文件制作、安装文件测试。具体内容如下: 创建VC++工程 打开 Visual Studio 2022,点击“新建项目”。 在弹出的“新建项目”窗口中,选择“Visual C++”分类,并在其中选择“Windows桌面向导”选项。 在下一个窗…

    C 2023年5月30日
    00
  • C/C++ 连接MySql数据库的方法

    连接MySQL数据库是C/C++开发人员需要掌握的一项基础技能。下面是连接MySQL数据库的方法: 安装MySQL连接库 要使用C/C++连接MySQL数据库,首先需要安装MySQL连接库。具体的安装步骤可以参考官方文档。在Linux系统下,可以使用以下命令安装: sudo apt-get install libmysqlclient-dev 连接MySQL…

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