C++智能指针

学习链接1

目录

智能指针概念

提供了一种自动管理动态分配内存的机制,可以避免手动管理内存所带来的问题,如内存泄漏和悬挂指针等。智能指针的主要目的是确保当对象不再需要时,其内存能够被自动释放。

std::unique_ptr

独享所有权:

  • 即不共享它的指针,也就无法复制给其他unique_ptr、无法值传递给函数、也无法用于需要副本的标准模板库STL算法;
  • 只能进行移动,也就是说将它的指针(内存资源所有权)转移给另一个unique_ptr,但是原始的unique_ptr将不再拥有此资源;也就是说std::unique_ptr是一个move_only的类型;
  • 默认情况下,智能指针的资源析构是伴随着调用std::unique_ptr内部的原始指针的delete操作。
    常用API:
  • 构造函数:用于创建unique_ptr实例。
  • reset():替换被管理对象,用空的unique_ptr替换也就是release()。
  • release():返回裸指针并放弃所有权,unique_ptr变为空。
  • get():返回裸指针,但不放弃所有权。
  • operator->() 和 operator*():重载了箭头运算符和解引用运算符,用于访问指向的对象。
cpp 复制代码
	std::unique_ptr<QString> pQString1(new QString("111"));

    std::unique_ptr<QString> pQString2;
    QString* str2 = new QString("222");
    pQString2.reset(str2);

    //std::make_unique方式在c++14才可使用
    std::unique_ptr<QString> pQString3 = std::make_unique<QString>("333");

    std::unique_ptr<QString> pQString4 = std::move(pQString3);// 转移所有权

使用场景:

  • 为动态申请的资源提供异常安全保证:当我们动态申请内存后,有可能我们接下来的代码由于抛出异常或者提前退出(if语句)而没有执行delete操作。使用智能指针即可避免这种情况
cpp 复制代码
void Func()
{
    int *p = new int(5);
    // ...(可能会抛出异常)
    
    delete p;
}
  • 返回函数内动态申请资源的所有权:
cpp 复制代码
unique_ptr<int> Func(int p)
{
    unique_ptr<int> pInt(new int(p));
    return pInt;    // 返回unique_ptr
}
int main() {
    int p = 5;
    unique_ptr<int> ret = Func(p);
    cout << *ret << endl;
    // 函数结束后,自动释放资源
}
  • 在容器中保存指针:
cpp 复制代码
int main() 
{
    vector<unique_ptr<int>> vec;
    unique_ptr<int> p(new int(5));
    vec.push_back(std::move(p));    // 使用移动语义
}
  • 管理动态数组;
  • 作为auto_ptr的替代品。

std::shared_ptr

介绍:

允许多个智能指针共享同一个对象的所有权。内部使用引用计数来追踪共享对象的所有权。当最后一个shared_ptr被销毁时,它所指向的对象才会被删除。(离开作用域即减少依次引用计数)。
常用API:

  • 构造函数:用于创建shared_ptr实例。
  • reset():释放当前管理的对象,并将shared_ptr置为空。
  • get():返回裸指针,但不放弃所有权。
  • use_count():返回当前共享对象的shared_ptr实例数。
  • unique():检查是否唯一拥有对象。
  • operator->() 和 operator*():重载了箭头运算符和解引用运算符。
cpp 复制代码
    std::shared_ptr<QString> pQString1(new QString("111"));// 分配内存
    std::unique_ptr<QString> pQString2 = pQString1;// 复制构造,增加引用计数
    // 当 sptr1 和 sptr2 都离开作用域时,内存才会被释放

std::weak_ptr

std::weak_ptr 是 C++11 引入的一个智能指针,它是对 std::shared_ptr 的一个补充。std::weak_ptr 不控制所指向对象的使用寿命,也就是说,它不会增加所指向对象的引用计数。其主要用途是观察一个由 std::shared_ptr 所管理的对象,而不会在对象的生命周期中持有所有权。

主要特性和用途

  • 不拥有对象(不增加引用计数):与 std::shared_ptr 不同,std::weak_ptr 不拥有其指向的对象。这意味着,当最后一个 std::shared_ptr 被销毁或重置时,即使还有 std::weak_ptr 指向该对象,对象也会被销毁。
  • 防止循环引用:当两个或更多的 std::shared_ptr 相互引用时,它们会形成一个循环引用,导致它们所指向的对象无法被正确销毁。通过使用 std::weak_ptr 来打破这种循环引用,可以确保对象在不再需要时被正确销毁。
  • 转换为 std::shared_ptr:尽管 std::weak_ptr 不拥有对象,但它可以安全地转换为 std::shared_ptr(如果对象仍然存在)。这种转换会增加对象的引用计数,确保在转换后的 std::shared_ptr 生命周期内对象不会被销毁。
  • 检查对象是否存在:可以使用 std::weak_ptr 的 expired() 成员函数来检查它所指向的对象是否仍然存在。

常用API:

  • 构造函数:通常通过shared_ptr或另一个weak_ptr来构造。
  • expired():检查所观察的对象是否已经被删除。
  • lock():尝试获取一个指向对象的shared_ptr。如果对象仍然存在,则返回一个指向它的shared_ptr;否则返回一个空的shared_ptr。
  • get():返回裸指针,但不参与对象的生命周期管理。
  • reset():将weak_ptr置为空。
cpp 复制代码
	std::shared_ptr<QString> pQString1(new QString("111"));// 分配内存
    std::weak_ptr<QString> pQString3(pQString1) ;//不增加引用次数

智能指针的优缺点

优点:自动内存管理、防止内存泄漏、防止野指针、防止重复释放、支持资源共享、异常安全、简化代码(不需要手动释放)、所有权和生命周期管理、支持自定义删除器

缺点:智能指针的使用可能会引入额外的性能开销(尽管通常这些开销是微不足道的)。需要正确理解和使用智能指针的所有权模型,以避免出现意外的行为。

相关推荐
Lzc77425 分钟前
C++初阶——简单实现vector
c++·简单实现vector
一个小白11 小时前
C++——list模拟实现
开发语言·c++
程序员老舅1 小时前
C++ Qt项目教程:WebServer网络测试工具
c++·qt·测试工具·webserver·qt项目·qt项目实战
靡不有初1112 小时前
CCF-CSP第18次认证第一题——报数【两个与string相关的函数的使用】
c++·学习·ccfcsp
cookies_s_s3 小时前
Linux--进程(进程虚拟地址空间、页表、进程控制、实现简易shell)
linux·运维·服务器·数据结构·c++·算法·哈希算法
不想编程小谭4 小时前
力扣LeetCode: 2506 统计相似字符串对的数目
c++·算法·leetcode
曼巴UE55 小时前
UE5.3 C++ TArray系列(一)
开发语言·c++·ue5
阿巴~阿巴~5 小时前
多源 BFS 算法详解:从原理到实现,高效解决多源最短路问题
开发语言·数据结构·c++·算法·宽度优先
CoderCodingNo6 小时前
【GESP】C++二级真题 luogu-b3924, [GESP202312 二级] 小杨的H字矩阵
java·c++·矩阵
刃神太酷啦7 小时前
堆和priority_queue
数据结构·c++·蓝桥杯c++组