C++之智能指针

(声明这是我自己的读书笔记,这个知识点还不了解,仅仅是记录自己看)

在C++中动态内存的管理是通过 new 在动态内存中为对象分配空间并返回一个指向该对象的指针; delete 接受一个动态对象的指针,销毁对象,并释放与之相关联的内存。使用动态内存的时候很容易出问题。

新标准提供了两种智能指针类型来管理动态对象:(它们可以自动负责释放所指向的对象)

shared_ptr 允许多个指针指向同一个对象;

unique_ptr 它独占所指向的对象。

还在一个名为 weak_ptr 的伴随类,它是一种弱引用,指向 shared_ptr所管理的对象。

它们三个都定义在头文件 memory 中。

标准库早版本包含了为一个名为 auto_ptr 的类 ,它具有 unique_ptr 的特性,但不是全部。虽然它仍然是标准库的一部分,但编写程序的时候应该使用 unique_ptr 。

shared_ptr:

智能指针也是模板,我们创建它的时候,必须提供它可以指向的类型,默认初始化的智能指针中保存着一个空指针。

shared_ptr <string> p1;
shared_ptr<list<int>> p2;

智能指针的使用方式和普通指针类似:

                   shared_ptr 和 unique_ptr 都支持的操作
shared_ptr <T> sp空智能指针,可以指向类型为T的对象
unique_ptr <T> up 
p将p用作一个条件判断,若p指向一个对象,则为真,否则为假
*p解引用p,获得它指向的对象
p -> mem等价于 (*p) . mem
p.get()返回p中保存的指针
swap (q, p)交换p 和 q的指针
p . swap (q)

下面是shared_ptr 独有的操作:

make_shared<T> (args)返回一个 shared_ptr ,指向一个动态分配的类型为T 的对象。使用 args 初始化此对象
shared_ptr <T>p(q)p是 shared_ptr q的拷贝;这个操作会递增q中的计数器,q中的指针必须能转换为 T*
p = qp和q都是shared_ptr,所保存的指针必须能相互转换,这个操作会递增q的引用计数,会递减p的引用计数;若p的引用计数变为0,则将其管理的原内存释放
p.unique()若p.use_count()为1,返回true,否则返回false
p.use_count()返回与p共享对象的智能指针数量 ,可能很慢,主要用于调试

make_ptr函数:

最安全的分配和使用动态内存的 方法是调用make_shared标准库函数,它也被定义在头文件memory中。

	shared_ptr<int> p3 = make_shared < int>  (999); //指向一个值为42的int的 shared_ptr
	shared_ptr<int> p4 = make_shared <int>(); //p4指向一个值初始化的Int,它的值为0

常用 auto 定义一个对象来保存 make_shared的结果比较简单。

	auto p3 = make_shared < int>  (999);

shared_ptr的拷贝与赋值:

当我们进行拷贝和赋值操作时,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象:

	auto p = make_shared < int>  (999); //p指向的对象在这里只有一个引用者
	auto q(p); //p和q指向相同的对象,这个对象有两个引用者
	cout << *q << '\n' << *p << endl;//输出相同的值

每个shared_ptr 都有一个关联的计数器,通常称为 引用计数。一旦一个shared_ptr的计数器变为0,它就会释放自己所管理的对象;

	auto r = make_shared<int>(520); //r指向的Int只有一个引用
	r = q;//给r赋值,令它指向另一个地址;递增q指向的对象的引用计数;递减r原来指向的对象的引用计数; r原来指向的对象已经没有引用者,会自动释放

shared_ptr 自动销毁所管理的对象,它也会自动释放相关联的内存。

运算符new分配内存,delete释放new分配的内存。

动态分配的对象是默认初始化的;
 

int* p = new int(10);//new返回是一个指向该对象的指针
	delete  p;

一个动态分配的const对象必须进行初始化,分配的对象是const的,new返回的指针是一个指向const的指针。

当new不能分配我们所要求的内存空间,它会抛出一个类型为 bad_alloc 的异常。

	int* p1 = new int; //如果分配失败,new抛出 std::bad_alloc
	int* p2 = new (nothrow) int; //如果分配失败,new返回一个空指针

我们可以改变使用new的方式来阻止它抛出异常:这种形式称为 定位new , 我们将 nothrow 传递给 new,我们意图是告诉它不能抛出异常。这种形式的new不能分配内存,它会返回一个空指针。

bad_alloc 和 nothrow 都定义在头文件 new 中。

动态内存的管理非常容易出错:

1.忘记 delete 内存。

2.使用已经释放掉的对象。

3.同一块内存释放两次。

我们在 delete 之后应该重置指针给指针赋值为 nullptr;清楚的指出指针不指向任何对象。

shared_ptr 和 new 结合使用:我们可以使用New返回一指针来初始化智能指针。

	shared_ptr <string> p1  (  new string ("hello")) ;//p1指向一个值为 hello 的string

接受指针参数的智能指针构造函数是 explicit(这种构造函数只能用于直接初始化) 的,必须使用直接初始化:(不能进行内置指针到智能指针的隐式转换)

	shared_ptr<int> p1 = new int(1024);//错误,必须使用直接初始化
	shared_ptr<int> p1(new int(999));//正确

默认情况下,一个用来初始化智能指针的普通指针必须指动态内存,因为智能指针默认使用 delete 释放它所关联的对象。我们要可以将智能指针绑定到一个指向其他类型的资源的指针上,为了这样做,我们必须提供自己的操作来替代 delete进行释放。

定义和改变 shared_ptr 的其他方法:

shared_ptr <T> p(q)p管理内置指针q所指的对象;q必须指向 new 分配的内存,且能够转换为 T* 类型
shared_ptr<T> p(u)p从 unique_ptr u 那里接管了对象的所有权;将u置为空
shared_ptr <T> p(q,d)p接管了内置指针q所指向的对象的所有权。q必须能转换为T*类型。p将使用可调用对象d来代替 delete
shared_ptr<T> p(p2,d)p是shared_ptr p2的拷贝,唯一的区别是P将用可调用对象d来代替 delete
p.reset()若p是唯一指向其对象的 shared_ptr , reset 会释此对象。若传递了可选的参数内置指针q ,会令P指向 q ;否则会将p 置为空。若还传递了参数 d ,将会调用d而不是 delete来释放 q
p. reset(q)
p.resrt(q,d)

不要混合使用普通指针和智能指针。

智能指针类型定义了一个名为get的函数,它返回一个内置指针,指向智能指针管理的对象。不要使用get 初始化另一个智能指针或为智能指赋值

使用智能指针的一些基本规范:

不使用相同的内置指针值初始化(或reser)多个智能指针。

不 delete get()返回的指针。

不使用 get() 初始化或 reset 另一个智能指针。

如果使用 get() 返回的指针 ,当最后一个对应的智能指针销毁后,指针就变为无效了。

如果使用智能指针管理的资源不是 new 分配的内存,要传递给它一个删除器(我们自己定义的一个函数代替delete , 这个函数必须能够完成对shared_ptr中保存的指针进行释放的操作)。

unique_ptr

当我们定义一个 unique_ptr时,需要将它绑定到一个new返回的指针上,初始化 unique_ptr 必须采用直接初始化。

unique_ptr<T> u1

unique_ptr<T,D> u2

空unique_ptr,可以指向类型为T的对象。u1会使用delete来释放它的指针;u2会使用一个类型为D的可调用对象来释放它的指针
unique_ptr<T,D> u(d)空unique_ptr,指向类型为T的对象,用类型为D的对象d代替 delete
u= nullptr释放u指向的对象,将u置为空
u.release()u放弃对指针的控制权,返回指针,并将u置为空
u.reset()释放u指向的对象
u.reset(q)如果提供了内置指针q,令u指向这个对象;否则将u置为空
u.reset(nullptr)

weak_ptr

weak_ptr 是一种不控制所指向对象生存周期的智能指针,它指向由一个shared_ptr 管理的对象。

wrak_ptr<T> w空 weak_ptr 可以指向类型为T 的对象
weak_ptr <T> w(sp)与shared_ptr sp 指向相同对象的 weak_ptr。T必须能转换为sp指向的类型
w=pp可以是一个shared_ptr或一个 weak_ptr。赋值后w与p共享对象
w.reset()将w置为空
w.use_count()与w共享对象的shared_ptr的数量 
w.expired()若w.use_count()为0,返回true,否则返回false
w.lock()如果expired 为true , 返回一个空 shared_ptr; 否则 返回一个指向w的对象的shared_ptr

当我们创建一个weak_ptr时,要用一个 shared_ptr来初始化它:

auto p = make_shared<int>(42);
	weak_ptr<int> wp(p);//wp弱共享p;p的引用计数没有改变
	cout<<*(wp.lock());

我们不能使用weak_ptr直接访问对象,必须调用 lock。它返回一个指向共享对象的shared_ptr。

以上内容来自《C++ primer》书中知识点读书总结。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

syhk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值