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

yizhihongxing

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日

相关文章

  • Java8 ArrayList之forEach的使用

    下面我将为你详细讲解“Java8 ArrayList之forEach的使用”的完整攻略。 1. Java8 ArrayList的使用 在Java中,ArrayList是一种常见的集合类型,它继承自List接口,可以存储多个元素,并且支持动态数组的特性,可以自动扩容。下面是ArrayList的定义: public class ArrayList<E&gt…

    C 2023年5月23日
    00
  • C++中函数指针详解及代码分享

    关于“C++中函数指针详解及代码分享”的完整攻略,我为大家总结如下: 1. 什么是函数指针? 函数指针是一个指向函数的指针变量。函数指针可以像普通函数一样被调用,其语法形式为: 返回值类型 (*指针变量名)(参数列表); 其中,指针变量名可以被赋值为相同参数列表和返回类型的函数地址。可以使用函数指针来传递函数作为参数、实现回调函数等。 举个例子,假如我们有一…

    C 2023年5月24日
    00
  • 逍遥自在学C语言 | 位运算符~的高级用法

    前言 在上一篇文章中,我们介绍了^运算符的高级用法,本篇文章,我们将介绍~ 运算符的一些高级用法。 一、人物简介 第一位闪亮登场,有请今后会一直教我们C语言的老师 —— 自在。 第二位上场的是和我们一起学习的小白程序猿 —— 逍遥。 二、相反数 我们可以利用负数的补码性质,来获得一个正数的相反数 #include <stdio.h> int ma…

    C语言 2023年4月17日
    00
  • Json对象和字符串互相转换json数据拼接和JSON使用方式详细介绍(小结)

    下面我将详细讲解“Json对象和字符串互相转换json数据拼接和JSON使用方式详细介绍(小结)”这个话题。此话题包括以下三个部分: Json对象和字符串互相转换 Json数据拼接 Json使用方式详细介绍 1. Json对象和字符串互相转换 在JavaScript中,我们可以使用JSON.stringify()方法将一个JavaScript对象序列化成一个…

    C 2023年5月23日
    00
  • c++二叉树的几种遍历算法

    让我来详细讲解一下C++二叉树的几种遍历算法。 什么是二叉树 二叉树是一种树形结构,每个节点最多只能有两个子节点。一个节点的左子树和右子树也是二叉树,称为该节点的左子节点和右子节点。 二叉树的遍历 二叉树的遍历指的是按一定规则依次访问二叉树中各个节点,并使每个节点被访问一次,且只访问一次。常用的二叉树遍历方法有前序遍历、中序遍历和后序遍历。 1. 前序遍历 …

    C 2023年5月22日
    00
  • 雅虎公司C#笔试题(后半部份才是)

    “雅虎公司C#笔试题(后半部份才是)”是一道常见于程序员面试和笔试的题目。下面就从如何解题的角度,为大家讲解完整攻略。 题目描述 题目大意是给出两个字符串,求它们在其中一个字符串中的最长公共子串。 具体需要完成的是,实现一个方法 string Find(string str1, string str2, string source),其中: 参数 str1 …

    C 2023年5月23日
    00
  • C程序 将一个数组的所有元素复制到另一个数组

    下面我来详细讲解如何编写一份 C 程序来将一个数组的所有元素复制到另一个数组。 问题描述 假设有两个整型数组 arr1 和 arr2,现在的任务是将 arr1 的所有元素复制到 arr2 中。 思路分析 这个问题可以通过创建一个循环来实现,遍历 arr1 的所有元素并将其逐个复制到 arr2 中。因此,我们将创建一个 for 循环,并在循环中执行一个赋值操作…

    C 2023年5月9日
    00
  • C语言结构体释放问题

    C语言中的结构体是一种自定义的数据类型,相对于其他基本数据类型,结构体可以描述更为复杂的数据结构。在程序中,我们通常需要申请、初始化、使用和释放结构体变量,其中释放结构体变量所占用的内存空间是非常重要的一步。本文将详细讲解C语言结构体释放问题的完整使用攻略,让读者能够正确地使用结构体并避免内存泄漏问题。 申请和释放结构体空间的注意点 在C语言中申请和释放结构…

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