欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 资讯 > 【C++11】智能指针

【C++11】智能指针

2025/1/3 17:32:10 来源:https://blog.csdn.net/qq_72680384/article/details/144852628  浏览:    关键词:【C++11】智能指针

目录

  • 指针
  • 标准库
    • unique_ptr
      • 对应类方法
      • 创建unique_ptr对象的两种方法
      • unique_ptr的使用
      • 特性
    • shared_ptr
      • 类方法
      • 循环引用造成内存泄漏
    • weak_ptr
      • weak_ptr的创建
      • 三个方法
      • 功能
      • 例子1
      • 例子2

指针

  • 普通指针:指向内存区域的地址变量
  • 当普通指针指向动态分配的内存的时候,即使这个指针变量离开了所在的作用域,这块内存也不会被自动销毁,动态分配的内存不进行释放,则造成了内存泄漏。
    在这里插入图片描述
  • 如果一个指针指向了一块已经被释放的内存区域,那么这个指针就是悬空指针,使用悬空指针会造成不可预料的结果。
    在这里插入图片描述
  • 定义了一个指针,却未初始化使其指向有效的内存区域时,这个指针就成了野指针,使用野指针访问内存,一般会造成segmentation fault 错误。
    在这里插入图片描述
  • 智能指针:封装了动态对象指针的类对象

使用智能指针,则可以有效的避免上述问题的发生。
智能指针是一个对象,它封装了指向另一个对象的指针,当智能指针离开作用域后,会被自动销毁,销毁过程中会调用析构函数来删除所封装的对象。
在这里插入图片描述

标准库

在标准模板库中提供了以下几种智能指针:

  • unique_ptr
  • shared_ptr
  • weak_ptr

unique_ptr

在创建智能指针时,你可以传入一个指向对象的类型和自定义的删除器,(删除器一般为默认不传)。
Deleter 是一个模板类,它用于定义如何释放智能指针管理的对象,可以被作为删除器。
在这里插入图片描述

unique_ptr与它所管理的动态对象是一对一的关系,不能有两个unique_ptr同时指向同一个地址。

对应类方法

  • get() — 用于获取所管理对象的指针
  • 重载的-> 成员运算符函数 — 调用了get函数,也是返回了所管理对象的指针
  • 重载的*成员运算符 — 返回所管理对象的引用,相当于*get()
  • release() — 智能指针释放对该地址的所有权,返回一个原始指针,由调用者去负责后续该地址的内存管理。
  • reset(T* newObject) — 会删除原有的对象,接管新的对象。
  • swap(unique_ptr<T>& other) — 交换所管理的对象

在这里插入图片描述

创建unique_ptr对象的两种方法

ptr1 指向new出来的对象。

	unique_ptr<A> ptr1(new A(参数))unique_ptr<A> ptr1 = make_unique<A>(参数)

unique_ptr的使用

  • unique_ptr不再指向当前对象的时候,会自动删除对象。
#include <iostream>
using namespace std;class Rectangle {
public:Rectangle(double w, double h) :width(w),height(h){}~Rectangle() { cout << "对象被释放" << endl; }double area() { return width * height; }
private:double width;double height;
};int main()
{unique_ptr<Rectangle> pDemo(new Rectangle(3.5, 4.1));pDemo = nullptr;cout << "分隔-------分隔"  << endl; //是否在这之前就将对象释放return 0;
}

特性

  • 由于unique_ptr 对所管理的资源具有独占性,所以unique_ptr的特性有不能被拷贝,不能被赋值。
  • 但可以通过move转移
  • 一般智能指针的大小与指针是相同的

shared_ptr

多个shared_ptr对象可以共同管理同一个指针。
它们通过一个共同的引用计数器来管理指针,例如,当有3个shared_ptr都指向一个对象时,引用计数器的值为3,当一个智能指针被销毁时,引用计数器-1,当计数器为0时,会将所指向的内存对象释放。

类方法

use_count() — 获得有多少个shared_ptr在共同管理同一个对象
unique() — 返回use_count是否等于1
在这里插入图片描述
在这里插入图片描述

循环引用造成内存泄漏

  • 以下代码均有两个智能指针分别指向张三,李四,王五。
  • 当people离开作用域被销毁后,会将每个Person对象的引用计数-1,但是每个Person对象的成员partner智能指针仍存在,所以无法自动删除person对象,导致内存泄。
class Person
{
public:Person(const string& name) :_name(name) { cout << "构造函数调用" << endl; }~Person() { cout << _name << "销毁" << endl; }void setPartner(const shared_ptr<Person>& other) { _partner = other; }
private:string _name;shared_ptr<Person> _partner;};int main()
{vector<shared_ptr<Person>> people;people.push_back(shared_ptr<Person>(new Person("张三")));people.push_back(shared_ptr<Person>(new Person("李四")));people.push_back(shared_ptr<Person>(new Person("王五")));people[0]->setPartner(people[1]);people[1]->setPartner(people[2]);people[2]->setPartner(people[0]);return 0;
}

weak_ptr

用来表示临时所有权,不会增加引用计数,需要结合shared_ptr使用。当需要临时所有权时,则将其转换为shared_ptr,这样对象的引用计数会+1,来保证正在访问对象的有效性。

weak_ptr的创建

  • 可以将一个share_ptr作为weak_ptr的构造函数参数来初始化。
  • 也可以直接将share_ptr赋值weak_ptr
    在这里插入图片描述

三个方法

  • use_count() — 返回引用计数
  • expired()— 用来检查与之关联的对象是否已经被销毁。如果对象已经被销毁(即 shared_ptr 的引用计数为 0),那么 expired()返回true;否则,返回false
  • lock() — 用于尝试将一个 weak_ptr 转换为shared_ptr。如果 weak_ptr观察的对象仍然存在(即 shared_ptr 的引用计数大于 0),那么 lock() 会返回一个有效的 shared_ptr,指向相同的对象。如果对象已经被销毁(引用计数为 0),那么lock()返回一个空的 shared_ptr

功能

控制块是在share_ptr第一次接管对象的时候创建的。
shared_ptr 决定 use_count 的值。
weak_ptr决定 weak_count 的值。
use_count值等于0时,释放对象。
在这里插入图片描述

例子1

  • w_p1不增加引用计数
  • s_p1,s_p2指向对象rectangle,所以计数为2。
  • 当退出作用域时,引用计数为0,释放对象。
    在这里插入图片描述

例子2

  • 创建临时所有权
  • 当引用计数>0时,返回有效的shared_ptr
  • 当引用计数为0时,返回空
    在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com