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);
函数外的对象以及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阅读笔记-第3章-标准库类型vector
- c++primer阅读笔记之数组与指针
- C++Primer阅读笔记-第3章-标准库类型 迭代器
- C++primer 阅读笔记-模板与泛型编程(模板参数)
- C++primer 阅读笔记-模板与泛型编程(成员模板)
- C++Primer阅读笔记-第4章-数组
- C++Primer阅读笔记-第3章-标准库类型 bitset类型
- c++primer阅读笔记之泛型算法
- C++primer阅读笔记---------------面向对象程序设计
- c++primer阅读笔记之关联容器学习
- C++Primer阅读笔记-第3章-标准库类型string
- C++primer阅读笔记----------拷贝控制
- C++primer阅读笔记---------泛型算法
- 【C++primer】一学期阅读笔记
- C++Primer阅读笔记-第9章-函数 形参
- C++primer第五版笔记-第十二章动态内存
- c++primer阅读笔记之函数
- C++primer(3版)第17章-类继承和子类型-阅读笔记
- C++primer阅读笔记-重载运算与类型转换(可调用对象与function)
- C++primer阅读笔记-模板与泛型编程(模板实参推断)