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

智能指针的优缺点

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

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

相关推荐
PluviophileDD1 小时前
【笔记】C语言转C++
c语言·c++
獨枭2 小时前
MFC 自定义编辑框:打造灵活的数据输入控件
c++·mfc
逆袭之路6662 小时前
浅谈右值引用 移动语义 完美转发 std::move std::forward,窥探模板元编程的一角
c++
安於宿命2 小时前
【Linux】文件系统
linux·服务器·c++
oioihoii2 小时前
C++ 中 std::array<int, array_size> 与 std::vector<int> 的深入对比
开发语言·c++
OTWOL2 小时前
预处理基础指南
开发语言·数据结构·c++·算法
老猿讲编程3 小时前
【零成本抽象】汽车嵌入式软件开发中零成本抽象的功能安全考量与应对策略
c++·安全·汽车·零成本抽象
ZPILOTE3 小时前
日志基础示例python和c++
c++·python·日志·log·logger·glog
ZLRRLZ3 小时前
【C++】继承
c++
codears4 小时前
Qt编写的文件传输工具
c++·qt