C++中的智能指针举例详解及注意事项

 更新时间:2025年03月29日 08:35:30   作者:MobiCetus  
智能指针是C++中用于管理动态分配资源的强大工具,通过正确使用智能指针,可以显著减少内存泄漏的可能性,这篇文章主要介绍了C++中的智能指针举例详解及注意事项的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

指针用于访问程序外部的资源——如堆内存。因此,访问堆内存(如果在堆中创建了任何内容)时,需要使用指针。当访问任何外部资源时,我们只使用该资源的副本。如果我们对其进行修改,我们只会改变副本的版本。但如果我们使用指针来访问资源,我们将能够修改原始资源。

C++ 中普通指针的一些问题如下:

内存泄漏:当程序反复分配内存但从未释放时,会导致内存泄漏。这会导致过度的内存消耗,最终可能导致系统崩溃。

悬空指针:悬空指针是指在对象从内存中被释放后,没有修改指针的值。此时,指针仍然指向已释放的内存。

野指针:野指针是已经声明并分配了内存的指针,但该指针从未初始化为指向有效的对象或地址。

数据不一致:数据不一致发生在一些数据存储在内存中,但没有以一致的方式更新。

// C++ 程序演示指针的工作方式
#include <iostream>
using namespace std;

class Rectangle {
private:
    int length;
    int breadth;
};

void fun() {
    // 使用指针 p 并动态创建一个 Rectangle 对象
    Rectangle* p = new Rectangle();
}

int main() {
    // 无限循环
    while (1) {
        fun();
    }
}

输出

Memory limit exceeded

解释:

在 fun 函数中,创建了一个指针 p,它指向一个 Rectangle 对象。这个对象包含两个整数:length 和 breadth。当 fun 函数结束时,指针 p 会被销毁,因为它是一个局部变量。然而,它占用的内存并没有被释放,因为我们忘记使用 delete p; 来删除它。这意味着内存不会被释放,无法供其他资源使用。虽然我们不再需要这个变量,但我们需要释放内存。

在 main 函数中,fun 函数被无限次调用。每次调用都会创建 p,但内存没有被释放。随着调用的进行,内存不断增加,但不会被回收。由于没有释放的内存,最终会导致内存泄漏,整个堆内存可能因此变得无用。

智能指针

正如我们不自觉地发现的那样,未释放指针会导致内存泄漏,可能会导致程序崩溃。Java、C# 等语言通过垃圾回收机制来智能地释放未使用的内存。C++ 也有自己的机制:智能指针。当对象被销毁时,智能指针会自动释放内存。因此,我们不需要手动调用 delete 来释放内存。

智能指针是一个指针的封装类,重载了像 * 和 -> 等操作符。智能指针类的对象看起来像普通指针,但与普通指针不同,它可以释放销毁的对象内存。

智能指针的思想是创建一个包含指针、析构函数和重载操作符(如 * 和 ->)的类。由于析构函数会在对象超出作用域时自动调用,因此动态分配的内存会自动被删除(或者引用计数会减少)。

// C++ 程序演示智能指针的工作方式
#include <iostream>
using namespace std;

class SmartPtr {
    int* ptr; // 实际指针
public:
    // 构造函数
    explicit SmartPtr(int* p = NULL) { ptr = p; }

    // 析构函数
    ~SmartPtr() { delete (ptr); }

    // 重载解引用操作符
    int& operator*() { return *ptr; }
};

int main() {
    SmartPtr ptr(new int());
    *ptr = 20;
    cout << *ptr;

    // 我们不需要调用 delete ptr:当对象 ptr 超出作用域时
    // 它的析构函数会自动被调用,析构函数会删除 ptr。

    return 0;
}

输出

20

指针与智能指针的区别

指针智能指针
指针是一个存储内存地址和该内存位置数据类型信息的变量。指针是指向内存中某个位置的变量。智能指针是一个指针封装的栈分配对象。简单来说,智能指针是封装指针的类。
它不会在作用域结束时销毁。它在作用域结束时会销毁自己。
指针没有额外的特性,效率较低。智能指针效率更高,因为它具有内存管理的附加功能。
指针是手动管理的。智能指针是自动管理的。

注意:

这仅适用于 int 类型。那我们必须为每个对象创建智能指针吗?不,解决方案是模板。如下所示,T 可以是任何类型。

示例:使用模板解决问题

// C++ 程序演示模板的工作方式,并解决指针问题
#include <iostream>
using namespace std;

// 通用智能指针类
template <class T> class SmartPtr {
    T* ptr; // 实际指针
public:
    // 构造函数
    explicit SmartPtr(T* p = NULL) { ptr = p; }

    // 析构函数
    ~SmartPtr() { delete (ptr); }

    // 重载解引用操作符
    T& operator*() { return *ptr; }

    // 重载箭头操作符,这样可以像指针一样访问 T 的成员
    T* operator->() { return ptr; }
};

int main() {
    SmartPtr<int> ptr(new int());
    *ptr = 20;
    cout << *ptr;
    return 0;
}

输出

20

注意:

智能指针也非常适用于资源管理,比如文件句柄或网络套接字等。

智能指针的类型

C++ 库提供了以下类型的智能指针实现:

  • auto_ptr

  • unique_ptr

  • shared_ptr

  • weak_ptr

auto_ptr

使用 auto_ptr,可以管理通过 new 表达式获取的对象,并在 auto_ptr 自身销毁时删除它们。当通过 auto_ptr 描述一个对象时,它会存储指向单个分配对象的指针。

注意:从 C++11 起,auto_ptr 被弃用。unique_ptr 是一个类似的功能,但它提供了更高的安全性。

unique_ptr

unique_ptr 只存储一个指针。我们可以通过移除当前对象并指向另一个对象来重新赋值。

实例

// C++ 程序演示 unique_ptr 的工作方式
// 这里我们展示 unique_ptr 指向 P1。
// 但是我们移除了 P1 并将其指向 P2,因此指针现在
// 指向 P2。

#include <iostream>
using namespace std;
// 动态内存管理库
#include <memory>

class Rectangle {
    int length;
    int breadth;

public:
    Rectangle(int l, int b)
    {
        length = l;
        breadth = b;
    }

    int area() { return length * breadth; }
};

int main()
{
    // 智能指针
    unique_ptr<Rectangle> P1(new Rectangle(10, 5));
    cout << P1->area() << endl; // 打印 50

    // unique_ptr<Rectangle> P2(P1);
    unique_ptr<Rectangle> P2;
    P2 = move(P1);

    cout << P2->area() << endl;

    return 0;
}

50
50

shared_ptr

通过 shared_ptr,多个指针可以同时指向同一个对象,它将使用 use_count() 方法来维护引用计数。

// C++ 程序演示 shared_ptr 的工作方式
// 这里智能指针 P1 和 P2 都指向同一个
// 对象,并且它们都会保持该对象的引用。

#include <iostream>
using namespace std;
// 动态内存管理库
#include <memory>

class Rectangle {
    int length;
    int breadth;

public:
    Rectangle(int l, int b)
    {
        length = l;
        breadth = b;
    }

    int area() { return length * breadth; }
};

int main()
{
    // 智能指针
    shared_ptr<Rectangle> P1(new Rectangle(10, 5));
    cout << P1->area() << endl;

    shared_ptr<Rectangle> P2;
    P2 = P1;

    cout << P2->area() << endl;

    cout << P1->area() << endl;
    cout << P1.use_count() << endl;
    return 0;
}

50
50
50
2

weak_ptr

weak_ptr 是一种智能指针,它持有一个非拥有的引用。它与 shared_ptr 非常相似,但不会维护引用计数。这样,指针不会对对象保持强引用,避免了通过 shared_ptr 创建的循环依赖问题。

// C++ 程序演示 weak_ptr 的工作方式
// 这里智能指针 P1 和 P2 都指向同一个
// 对象,但它们都不保持对象的引用。

#include <iostream>
using namespace std;
// 动态内存管理库
#include <memory>

class Rectangle {
    int length;
    int breadth;

public:
    Rectangle(int l, int b)
    {
        length = l;
        breadth = b;
    }

    int area() { return length * breadth; }
};

int main()
{
    // 智能指针
    shared_ptr<Rectangle> P1(new Rectangle(10, 5));
  
    // 创建 weak_ptr
    weak_ptr<Rectangle> P2(P1);
  
    cout << P1->area() << endl;
    cout << P1.use_count() << endl;
    return 0;
}

50
1

总结

到此这篇关于C++中的智能指针举例详解及注意事项的文章就介绍到这了,更多相关C++智能指针内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 虚函数被类的构造析构函数和成员函数调用虚函数的执行过程

    虚函数被类的构造析构函数和成员函数调用虚函数的执行过程

    虚函数被类的构造析构函数和成员函数调用虚函数的执行过程,需要的朋友可以参考下
    2013-02-02
  • C++ OpenCV中几种基本的图像处理方式

    C++ OpenCV中几种基本的图像处理方式

    大家好,本篇文章主要讲的是C++ OpenCV中几种基本的图像处理方式,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • C++学习笔记之类成员指针

    C++学习笔记之类成员指针

    类成员指针时指可以指向类的非静态成员的指针,下面这篇文章主要给大家介绍了关于C++类成员指针的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • Clion下载安装使用的详细教程(Win+MinGW)

    Clion下载安装使用的详细教程(Win+MinGW)

    这篇文章主要介绍了Clion下载安装使用教程(Win+MinGW),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • C++超详细讲解内存空间分配与this指针

    C++超详细讲解内存空间分配与this指针

    this 指针在C++类和对象中是个很方便实用的关键字,可以简化对象成员属性的调用,使代码表达的含义更加准确;在之前的学习中我们都可以判断变量所占内存空间大小,那么我们创建的类对象所占的内存空间怎么计算呢?想知道this的妙用和类对象占用的内存空间就来跟我学习吧
    2022-05-05
  • C语言函数之memcpy函数用法实例

    C语言函数之memcpy函数用法实例

    memcpy函数用于把资源内存(src所指向的内存区域)拷贝到目标内存(dest所指向的内存区域),下面这篇文章主要给大家介绍了关于C语言函数之memcpy函数用法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • Matlab实现简易纪念碑谷游戏的示例代码

    Matlab实现简易纪念碑谷游戏的示例代码

    《纪念碑谷》是USTWO公司开发制作的解谜类手机游戏,在游戏中,通过探索隐藏小路、发现视力错觉以及躲避神秘的乌鸦人来帮助沉默公主艾达走出纪念碑迷阵。本文将用Matlab编写简易版的纪念碑谷游戏,感兴趣的可以了解一下
    2022-03-03
  • C语言数组超详细讲解中篇三子棋

    C语言数组超详细讲解中篇三子棋

    数组是一组有序的数据的集合,本篇将带你结合数组来实现三子棋小游戏,上手实练更快的能够掌握数组使用,感兴趣的朋友来看看吧
    2022-04-04
  • C++实现LeetCode(105.由先序和中序遍历建立二叉树)

    C++实现LeetCode(105.由先序和中序遍历建立二叉树)

    这篇文章主要介绍了C++实现LeetCode(105.由先序和中序遍历建立二叉树),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • 基于C语言实现五子棋游戏

    基于C语言实现五子棋游戏

    这篇文章主要为大家详细介绍了基于C语言实现五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11

最新评论