0
点赞
收藏
分享

微信扫一扫

C++ 动态内存 《C++Primer》第12章 读书笔记

MaxWen 2022-03-13 阅读 60
c++

1、智能指针

1.1 两种智能指针shared_ptrunique_ptr

共有操作:

在这里插入图片描述

  • 注意:get函数返回的是内置类型的指针,不是智能指针
这样理解shared_ptrshared_ptr类型的对象可以【共享所有权】,并且可以【分享该所有权】,一旦他们取得了一个指针的所有权,那么当该指针的这一组所有者中【最后一个释放所有权】的需要负责【释放该指针所指向的内存空间】。
shared_ptr对象只能通过复制其值来共享所有权。



shared_ptr独有的操作:

在这里插入图片描述

  • 使用make_shared构造对象时,如果不传递任何参数,对象就会进行值初始化。
  • 在刚刚初始化一个shared_ptr后,他的计数器是否为1或0,在于初始化的时候到底有没有给他一个实际分配了的堆内存空间。

2、直接管理内存(不用智能指针,而是用newdelete

2.1 使用new动态分配和初始化对象

默认情况下(就是只写一个类型在那里),用new动态分配的对象时默认初始化的。(注意不是值初始化)
但我们可以在初始化的时候使用 直接初始化(()里面直接写上初值) 、构造函数初始化 、 列表初始化 、以及值初始化(只写一个())。
在这里插入图片描述

动态分配const对象:

const int *pci = new const int(1024);
const string pcs = new const string;

内存耗尽:

int *p1 = new int;					如分配失败,new抛出异常std::bad_alloc
int *p2 = new (nothrow) int;		若分配失败,返回空指针,不抛出异常

2.2 delete

delete用于释放内置指针指向的动态分配的对象所占用的动态内存空间。

  • delete可以释放【任何】空指针,即使他不是指向动态内存
  • delete不能释放非new定义的指针,准确来说是不能释放指向局部变量(栈空间)的指针
  • delete不能两次释放同一个指针
  • 不能释放非指针变量
  • const对象也是可以被销毁的
  • delete一个指针后,指针值就无效了,虽说他还保存着(已经释放了的)动态内存的地址,但里面已经没有数据对象了。最好把它置为nullptr

2.3 练习题

在这里插入图片描述
答案和分析:
有错误。
上面的函数意图通过new返回的指针来判断内存分配成功或失败,若成功,返回合法指针,指针转换成bool类型的true,若p得到nullptr则转换为false
但普通new调用在【分配失败】时抛出一个【异常bad_alloc】,而不是返回nullptr,因此程序不能达到预期的目的。
进行如下修改阻止抛出异常:

int* p = new (nothrow) int;

不过最佳的方法是捕获异常,或判断返回的指针来返回truefalse,而不是依赖类型转换。

3、shared_ptrnew 的混合使用

可以用new返回的指针初始化智能指针,如下所示:

shared_ptr<int> p(new int(42));		p2指向值为42int
但需要注意:只能使用直接初始化方式。

因为接收参数的智能指针构造函数是explicit的,所以不能将一个内置指针隐式转换为一个智能指针,必须直接初始化:

shared_ptr<int> p1 = new int(42);		错误,隐式地要求用int*来转换成shared_ptr
shared_ptr<int> p2(new int(42));		正确

shared_ptr<int> clone(int p)			尤其在函数里要小心这种隐式转换
{
	return new int(p);					隐式转换为shared_ptr
}

同理,一个shared_ptr的指针,也不能隐式的转换为一个普通(内置)指针。

4、shared_ptr的其他构造方法 以及 成员

在这里插入图片描述在这里插入图片描述
最好不用内置指针访问之智能指针所指的对象,因为不知道对象和时会被销毁。内置指针很可能会变成悬空的。

5、使用智能指针的注意事项

在这里插入图片描述

6、unique_ptr特有的操作

6.1 初始化方法

不可赋值初始化,或拷贝初始化。

unique_ptr<int> u1(new int(42));		通过构造函数,直接初始化
unique_ptr<int> u2 = move(u1);			通过移动函数初始化,当然了,u1已经无了

6.2 unique_ptr的操作

在这里插入图片描述

  • unique_ptr和对象绑定在一起,所以没有拷贝 和 赋值操作
  • 但是,成员releasereset共同使用可移交指针的所有权
  • release返回的是【内置】指针类型。
  • release这种【不会释放对象】的操作,我们应该用一个指针或智能指针保存release返回的指针,防止其丢失,并且要记得delete掉这个指针。
  • unique_ptr也有get方法,但通常仅用于拿到指针,然后访问内存里的数据,一旦unique_ptr被释放了,这个指针就不要用了。

6.3 unique_ptr不能拷贝的例外

1:
unique_ptr<int> aaa()
{
	unique_ptr<int> u1(new int());
	// 函数的代码
	return u1;								返回值时发生了拷贝				
}2:
unique_ptr<int> bbb()
{
	// 函数的代码
	return unique_ptr<int>(new int(42));	返回值时发生了拷贝
}

6.4 指向数组的unique_ptr(动态数组)(不做重点)

在这里插入图片描述

  • u指向动态分配的数组,调用u.release(),会自动用delete[]销毁其内存空间和指针。
  • shared_ptr不支持管理动态数组,如果希望使用shared_ptr管理,需要提供自定义的删除器。而且,shared_ptr也不支持下标访问元素。必须通过get获取内置指针来访问。

7.1 weak_ptr

weak_ptr不共享内存对象的所有权,也就是,他不会控制所指对象的生存期,即使它指向了shared_ptr所管理的对象,也不会另相应shared_ptr计数器增加。这就叫weak
在这里插入图片描述

  • 注意lock成员返回的是一个shared_ptr,所以会递增相应的计数器

8、allocator分配器

8.1 标准库分配器及其成员

在这里插入图片描述

  • 不要用allocate返回的指针去构造,而是应该用另一个指针接收它的值,用另一个指针构造,开始的指针最后用来释放内存。
  • construct没有返回值,所以每构造完一个对象,你都得手动++指针,只想下一片内存,才能继续构造。
allocator<int> alloc;
auto const p = alloc.allocate(10);	
auto m = p;

alloc.construct(m++);				构造空 string
alloc.construct(m++, 10, 'c');		10'c'的string		  'construct''args'参数可以是这些
alloc.construct(m++, "hi");			"hi"

while (m != p)
	alloc.destroy(--q);				释放的时候,先  'destroy'
	
alloc.deallocate(p, 10);			最后一步

8.2 allocator算法

在这里插入图片描述

  • 经检验,虽说上述4个函数的参数 be 是说传迭代器,但是传递一个指针也是没有问题的,指针的类型就是allocate返回的指针类型。就是下面的这一长串:
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *
举报

相关推荐

0 条评论