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日

相关文章

  • Java异常 Exception类及其子类(实例讲解)

    Java异常 Exception类及其子类(实例讲解) 在Java中,异常是指在程序运行过程中发生的不正常情况,需要由程序对其进行处理以保障程序正常运行。Java异常类型分为Error和Exception,其中Error是指不可恢复的错误,如内存不足等;Exception则是可被捕获和处理的异常。 在Exception类中,又存在多个子类,每个子类可以处理不…

    C 2023年5月23日
    00
  • java与C 代码运行效率的对比(整理)

    Java与C代码运行效率的对比 背景与问题 在实际的程序开发过程中,我们经常需要选择一种适合的编程语言来编写程序。一般来说,我们选择的编程语言需要具备高效的运行效率,能够在较短的时间内完成程序的运行。 在选择编程语言时,我们往往需要考虑到该语言的运行效率。Java和C是两种常见的编程语言,那么Java和C的运行效率究竟如何呢? Java和C的运行效率对比 J…

    C 2023年5月23日
    00
  • C++程序操作文件对话框的方法

    现在我将为大家介绍一下在C++程序中操作文件对话框的方法。操作文件对话框是一个常用的功能,它可以帮助我们在程序中以交互式的方式选择文件并进行相关操作。下面是该攻略的详细步骤: 1. 确定操作系统类型 在编写代码之前,我们需要确定我们所使用的操作系统类型,不同的操作系统可能具有不同的文件对话框API接口。下面是Windows和macOS操作系统下涉及到的API…

    C 2023年5月23日
    00
  • Linux上搭建C/C++IDE开发环境

    在Linux上搭建C/C++IDE开发环境 1. 安装需要的工具 首先,我们需要安装一些必要的工具来搭建C/C++IDE开发环境。建议使用Ubuntu或者Debian系统,以下命令以Ubuntu为例: sudo apt-get update sudo apt-get install build-essential sudo apt-get install g…

    C 2023年5月23日
    00
  • QT设计秒表功能(跑步计时器)

    下面是关于QT设计秒表功能的完整攻略: 准备工作 安装QT开发环境 打开QT Creator,新建一个Qt Widgets Application项目 实现步骤 在项目中添加两个 Label 控件,一个用于显示当前计时的时间,另一个用于显示跑步时间,并设置好它们的位置和大小。 添加两个按钮,一个用于开始/暂停计时,另一个用于清零并停止计时。 对按钮和 Lab…

    C 2023年5月22日
    00
  • C语言函数指针和字符串

    让我们来详细讲解一下“C语言函数指针和字符串”的使用攻略。 函数指针 定义函数指针 函数指针是指向函数的指针。在C语言中,我们可以通过以下方式定义函数指针: 返回值类型 (*指针变量名)(参数列表) 例如,下面是一个函数指针的定义示例: int (*func_ptr)(int, int); 上面的代码定义了一个名为func_ptr的函数指针,它可以指向一个返…

    C 2023年5月9日
    00
  • Go 使用Unmarshal将json赋给struct出错的原因及解决

    问题描述 在使用Go语言的Unmarshal函数将json数据赋给struct时,可能会遇到一些出错的情况。 下面是一个例子: package main import ( "encoding/json" "fmt" ) type Person struct { Name string Age int } func ma…

    C 2023年5月23日
    00
  • Javascript技术难点之apply,call与this之间的衔接

    JavaScript中的this是编写JavaScript代码时最容易出错的概念之一。它不是指向函数本身,而是指向函数被调用时的当前对象。本文将讨论JavaScript中this的实现方式,以及用JavaScript中的apply和call方法来准确处理this的使用。 基本概念 this:一个特殊的关键字,指向正在执行的函数在哪个对象中被调用; apply…

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