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

智能指针的优缺点

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

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

相关推荐
情深不寿3175 分钟前
C++----STL(string)
开发语言·c++
boss-dog7 分钟前
C++内存泄露排查
c++·内存泄露
旧物有情16 分钟前
蓝桥杯历届真题 # 数字诗意(C++,Java)
java·c++·蓝桥杯
青い月の魔女1 小时前
初识C++(二)
开发语言·c++·笔记·学习
Verdure陌矣1 小时前
C++项目目录结构以及.vscode文件下的文件详解
开发语言·c++·vscode
多多*4 小时前
初识JVM HotSopt 的发展历程
java·开发语言·jvm·c++·学习·算法
一个平凡而乐于分享的小比特5 小时前
深拷贝与浅拷贝
c++·深拷贝与浅拷贝
白鹭float.5 小时前
【OpenGL/Assimp】渲染模型、半透明材质与封装光源
c++·图形学·opengl·assimp
捕鲸叉5 小时前
弥散张量分析开源软件 DSI Studio 简体中文汉化版可以下载了
c++·医疗影像
StudyWinter5 小时前
【OpenCV(C++)快速入门】--opencv学习
c++·学习·计算机视觉·openev