【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时,返回空
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值