目录
智能指针概念
提供了一种自动管理动态分配内存的机制,可以避免手动管理内存所带来的问题,如内存泄漏和悬挂指针等。智能指针的主要目的是确保当对象不再需要时,其内存能够被自动释放。
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) ;//不增加引用次数
智能指针的优缺点
优点:自动内存管理、防止内存泄漏、防止野指针、防止重复释放、支持资源共享、异常安全、简化代码(不需要手动释放)、所有权和生命周期管理、支持自定义删除器
缺点:智能指针的使用可能会引入额外的性能开销(尽管通常这些开销是微不足道的)。需要正确理解和使用智能指针的所有权模型,以避免出现意外的行为。