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日

相关文章

  • C++代码实现逆波兰表达式

    下面我来给您详细讲解C++代码实现逆波兰表达式的完整攻略。 什么是逆波兰表达式 逆波兰表达式,也叫后缀表达式,在数学、计算机科学中是一种存储和计算算术表达式的方法,其中每个运算符都跟在它的操作数之后。逆波兰表达式不需要括号来标识操作符的优先级。这种语法结构可避免我们所谓的”运算符优先级”。 举个例子,中缀表达式:1 + 2 * 3 – 4 / 2 的逆波兰表…

    C 2023年5月24日
    00
  • C程序 计算矩阵对角线之和

    下面是“C程序 计算矩阵对角线之和”的使用攻略。 程序功能说明 本程序通过输入矩阵的行列数以及矩阵元素,计算出矩阵的对角线之和。矩阵可以是正方形矩阵或长方形矩阵,支持浮点数和整数类型的元素。 程序使用说明 环境准备 在运行本程序前,需要确保您的电脑上已经安装了GCC编译器、C语言库以及相关的开发工具。 程序下载 您可以在网上搜索“矩阵对角线之和C程序下载”,…

    C 2023年5月9日
    00
  • C语言实现堆的简单操作的示例代码

    C语言实现堆的简单操作的示例代码 堆的定义 堆是指通过比较之后使得数组满足大/小根堆性质的一种近似完全二叉树结构。 堆的结构 堆有两种类型,分别为大根堆和小根堆。大根堆指所有父结点都大于等于其子结点,小根堆则相反,所有父结点都小于等于其子结点。 假设i为当前结点,那么其父结点为(i-1)/2,左子结点为(2i+1),右子结点为(2i+2)。 堆支持如下操作:…

    C 2023年5月23日
    00
  • 解决找不到模块“xxx.vue”或其相应的类型声明问题

    要解决找不到模块“xxx.vue”或其相应的类型声明问题,需要进行以下几个步骤: 步骤一:确认模块路径是否正确 在使用import导入组件时,首先需要确认导入的组件路径是否正确。如果路径不正确,系统将会无法找到组件,然后报出找不到模块的错误。在Vue项目中,我们可以使用@符号来代表项目根路径。 示例一: 假设我们在组件src/components/myCom…

    C 2023年5月23日
    00
  • 荣耀畅玩8c怎么切换应用?荣耀畅玩8c切换应用程序方法

    荣耀畅玩8c怎么切换应用? 切换应用程序方法 荣耀畅玩8c采用的是EMUI 8.2系统,在该系统下,切换应用程序有以下几种方法: 方法一:使用应用切换键 荣耀畅玩8c的系统底部有一个虚拟的按键区域,其中最左边的按键为 应用切换键 。使用该按键切换应用程序的具体步骤如下: 点击 应用切换键 ,系统会显示最近打开的应用程序列表; 在列表中选择要切换的应用程序,点…

    C 2023年5月23日
    00
  • javascript跨域方法、原理以及出现问题解决方法(详解)

    让我来详细讲解一下“javascript跨域方法、原理以及出现问题解决方法(详解)”。 什么是跨域 在浏览器中,当页面A通过请求其他域下的页面B中的资源时,浏览器会提示跨域错误,这时候就涉及到了跨域问题。一般来说跨域指的是协议、域名、端口号中任意一个不同就会造成跨域问题。 跨域解决方法 JSONP JSONP是通过在页面中插入一个script标签,通过获取一…

    C 2023年5月23日
    00
  • vs怎么做C窗体应用程序启动界面? vs2010窗体应用教程

    要在VS中制作C窗体应用程序的启动界面,可以按照以下步骤进行操作: 步骤一:创建新的窗体应用程序项目 在VS中选择 文件 -> 新建 -> 项目,在弹出的窗口中选择 Visual C++ -> Windows桌面 -> 窗体应用程序。命名新项目并选择已存在的文件夹,然后点击“确定”按钮确认创建。 步骤二:添加源码文件 在 VS 窗体应…

    C 2023年5月23日
    00
  • 详解C++11中的线程锁和条件变量

    详解C++11中的线程锁和条件变量 C++11中提供了一系列的线程同步机制,包括线程锁和条件变量。线程锁主要是为了保护共享资源,防止多个线程同时对同一块内存区域进行操作而发生冲突;而条件变量则主要是为了线程之间的协作,当一个线程等待某个条件成立时,可以通过条件变量来阻塞当前线程,直到条件被满足为止。 线程锁 Mutex Mutex(互斥锁)是最基本的线程锁,…

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