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) ;//不增加引用次数

智能指针的优缺点

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

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

相关推荐
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
郝学胜_神的一滴2 天前
CMake 034:生成器表达式:解耦构建时序、精简分支逻辑的终极利器
c++·cmake
见过夏天3 天前
C++ 基础入门完全指南
c++
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
BadBadBad__AK5 天前
线段树维护区间 k 次方和
c++·数学·算法·stl
卷无止境5 天前
Eigen 库如何借助 OpenMP 加速计算
c++·后端
卷无止境5 天前
OpenMPI、MPICH 与 OpenMP:关系、核心概念与架构全解
c++·后端
郝学胜_神的一滴6 天前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
卷无止境8 天前
C++ 的Eigen 库全解析
c++
卷无止境8 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端