您的位置:首页 > 编程语言 > C语言/C++

C++primer 阅读笔记---------------动态内存

2017-08-20 20:32 337 查看
该博客用于记录自己在阅读过程中不懂的知识点,很少用到但比较重要的知识点以及模棱两可的知识点

函数外的对象以及static对象, 类的static数据成员存储在静态内存,使用之前分配,程序结束销毁,栈内存用于保存函数内的非static变量,仅在该内存块存在,而动态分配的对象则存储在堆中

为了内存的安全,新的标准库提供类两种智能指针,shared_ptr允许多个指针指向同一个对象,unique_ptr独占式,还有一个week_ptr伴随类,它是一种弱引用,指向shared_ptr所管理的对象

shared_ptr<T> sp

unique_ptr<T> up

p.get() //返回p中保存的内置指针,如果智能指针释放类它的对象,则 返回指针所指对象也就没了

swap(p1, p2)

p1.swap(p2)

shared_ptr独有的操作

make_shared<T> (args) //返回一个shared_ptr,指向一个动态内存分配 的类型为T的对象,args初始化,最安全,替代 new

shared_ptr<T>p(q) //p是q的拷贝,q中的指针必须要能转换为 T*,并且q中的计数器会增加

p = q //会递减p原来指向对象的引用计数,递增q

p.unique() //若p.use_count()为1,则为true,否则false

p.use_count() //返回与p共享对象的只能指针数,效率可能很 慢,多用于调试

使用动态内存的原因大概有三个:

不知道自己需要使用多少对象 //容器类的元素都在堆上

不知道所需对象的准确类型

需要在多个对象间共享数据

虽然使用new和delete直接管理内存不安全,但我们还是应该了解

当使用new时,使用定位new向new传递额外参数

int *p = new (nothrow) int; //分配失败返回空指针,不再抛异常

指针delete过后,就变成类空悬指针,指向一块曾经保留数据对象但现在已经无效的内存的指针

接受指针参数的智能指针构造函数是explicit的,所以我们不能将一个内置指针隐式转换为一个智能指针

shared_ptr<int> p1 = new int(1024) //错误, 拷贝,不能隐式转换

shared_ptr<int> p1 (new int(1024)) //正确,直接初始化形式

统样的道理,返回时:

shared_ptr<int> clone(int p) {

return new int(p); //错误

return shared_ptr<int> (new int(p)); //正确

}

shared_ptr<T> p(q) //使用只能指针p管理内置指针q使用new分配的内存块

shared_ptr<T> p(u) //p从u(unique_ptr)那接管对象所有权,u置为空

shared_ptr<T> p(q, d) //使用可调用对象d替代delete

shared_ptr<T> p(p2, d) //p是p2的拷贝,但使用可调用对象d替代delete

p.reset() //将p置为空

p.reset(q) //p指向q

p.reset(q, d)

尽量避免混合使用内置指针和只能指针,也不要用get初始化另一个智能指针或者为另一个智能指针赋值

unique_ptr没有shared_ptr的make_shared(),定义unique_ptr时,需要绑定一个new返回的指针上,和shared_ptr一样必须采用直接初始化形式

unique_ptr<T> u1

unique_ptr<T, d> u2

unique_ptr<T, d> u(D) //类型为d的对象D代替delete

u = nullptr

u.release() //u放弃对指针的控制权,返回内置指针,将u置为空

u.reset() //释放对象

u.reset(q) //如果内置指针q存在,则u指向此对象,否则置为空

u.reset(nullptr)

unique_ptr不能拷贝或赋值,但有个例外,可以拷贝或赋值一个将要被销毁的

unique_ptr<int> clone(int p){

return unique_ptr<int> (new int(p));

}

或者返回一个局部对象的拷贝

unique_ptr<int> clone(int p){

return unique_ptr<int> ret(new int(p));

}

这种拷贝比较特殊,后面讨论它的特殊原因(挖坑)

weak_ptr是一种弱共享的指针,它必须指向一个由shared_ptr管理的对象,但weak_ptr不会影响计数器,因此不能直接使用weak_ptr,借助lock(),同时创建一个weak_ptr时要用一个shared_ptr来初始化

auto p = make_shared<int>(10);

weak_ptr<int> wp(p);

if(shared_ptr<int> np = wp.lock()){ //当wp指向的对象已经被销毁时返 回空的shared_ptr,if不成立

}

weak_ptr<T> w

weak_ptr<T> w(sp)

w = p

w.reset()

w.use_count() //与w共享对象的shared_ptr的数量

w.expired() //w.use_count()为0返回true

w.lock()

使用new动态分配的数组实际上得到的是一个数组元素类型的指针,所以不能对动态数组调用begin和end

可以使用智能指针管理动态数组,当管理的是动态数组时可以下标访问

unique_ptr<int []> up(new int[10]);

up[0] = i;

使用new缺乏一定的灵活性,因为它将内存分配和对象构造结合在了一起,delete类似,allocator类将内存分配和对象构造分开来

allocator<T> a //定义了一个allcator对象,它可以为类型为T的对象 分配内存

a.allocate(n) //分配保存n块T类型的对象的内存

a.deallocate(p, n) //释放从p开始的内存,该内存保存了n个T类型对象, 此时p和n必须和分配时一样,释放前要对其中的对 象执行destroy()

a.constructor(p, args) //p是一个类型为T*的指针,在p所指内存构建一 个对象,args被传递给所构建对象的构造函数

a.destroy(p) //p为T*指针,对所指对象执行析构函数

uninitialized_copy(b, e, p2); //b,e迭代器范围内的元素拷贝到p2迭代 器指定的原始内存

uninitialized_copy_n(b, n, p2); //迭代器b开始,拷贝n个

uninitialized_fill(b, e, t); //b,e范围创建对象,值为t

uninitialized_fill_n(b, n, t);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ primer