Chapter12:动态内存
- 智能指针——shared_ptr
为了更容易地使用动态内存,新的标准提供了智能指针来管理动态对象。智能指针的行为类似常规指针,重要的区别是它负责自动释放指向的对象。
智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。
if (p1 && p1->empty())
最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数
make_shared<T>(args); //返回一个shared_ptr, 指向一个动态分配的类型为T的对象,使用args初始化此对象。
shared_ptr自动销毁所管理的对象,还会自动释放相关联的内存。
shared_ptr在无用之后仍然保留的一种可能是:你将shared_ptr存放在一个容器中,随后重排了容器,从而不在需要某些元素。这个时候你应该确保使用erase删除那些不再需要的shared_ptr的元素。
- 使用了动态生存期的资源的类
(三种情况)
1. 程序不知道自己需要使用多少对象;例如容器类。
2. 程序不知道所需对象的准确类型;例如派生与继承。
3. 程序需要在多个对象间共享数据;到目前为止,我们使用过的类中,分配的资源都与对应对象生存期一致;但某些类分配的资源具有与原对象相独立的生存期,即:当某个对象被销毁时,我们不能单方面地销毁底层数据。
定义需要共享数据的类时,重点要考虑的是初始化、赋值、拷贝、销毁等拷贝控制得问题。
- 直接管理内存:new/delete
初始化:
默认情况下,动态分配的对象时默认初始化的,这意味着内置类型或组合类型的对象的值是未定义的,而类类型对象将用默认构造函数进行初始化;
对于定义了自己的构造函数的类类型来说,要求值初始化没有意义;不管采用什么形式,对象都会通过默认构造函数来初始化;
string *ps1 = new string; //默认初始化为空string
string *ps2 = new string(); //默认初始化为空string int* pi1 = new int;//默认初始化;*pi1的值未定义
int* pi1 = new int(); //值初始化为0
delete:
释放一块并非new分配的内存,或者将相同的指针值释放多次,其行为是未定义的。
动态对象的生存期知道被释放时为止;
delete之后的指针值就变为无效了。虽然指针已经无效,但是很多机器上指针仍然保存着动态内存的地址。此时指针就变为空悬指针(dangling pointer),最好在delete之后将nullptr赋予指针。
动态内存的一个基本问题是:可能多个直着你指向相同的内存,而在实际系统中,查找相同内存的所有指针是异常困难的。
- shared_ptr+new
接受指针参数的智能指针构造函数是explicit的,因此我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式。
shared_ptr<int> p1 = new int();//错误,必须使用直接初始化形式
shared_ptr<int> p2(new int());//正确,使用直接初始化形式
不要混合使用普通指针和智能指针——以防止同一块内存绑定到多个独立创建的shared_ptr上——推荐使用make_shared,而不是new。
void process(shared_ptr<int> ptr)
{//参数按值传递,发生拷贝操作
} shared_ptr<int> p(new int());
process(p);//在process中引用计数为2
int i = *p;//引用计数为1 int *x(new int());//x是普通指针
process(x);//错误
process(shared_ptr<int>(x));//会释放x的内存
int j = *x;
当将一个shared_ptr绑定到一个普通指针时,我们就将内存管理责任交给了这个shared_ptr。一旦这样做了,我们就不应该再使用内置指针来访问shared_ptr所指向的内存了;
使用一个内置指针来访问一个智能指针所负责的对象时很危险的,因为我们无法知道对象何时会被销毁。
不要使用get初始化另一个智能指针或为智能指针赋值——以防止同一块内存绑定到多个独立创建的shared_ptr上。
unique():在改变对象之前,我们要检查自己是否是当前对象的仅有的用户。如果不是,在改变之前,我们可能需要制作一份新的拷贝。
if (!p.unique())
p.reset(new string(*p));
智能指针使用规范:
1. 不使用相同的内置指针值初始化(或reset)多个智能指针;
2. 不 delete get()返回的指针;
3. 不使用get()初始化或reset另一个智能指针;
4. 如果使用了get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变成无效了;
5. 如果你使用智能指针管理的资源不是new分配的内存,记住传递一个删除器给它。
- 动态数组
标准库提供了一个可以管理new分配的数组的unique_ptr版本。为了用一个unique_ptr管理动态数组,我们必须在对象类型后面加一对空括号:
unique_ptr<int []> up(new int[]>;
up.release();//自动用delete[]销毁其指针
与unique_ptr不同,shared_ptr不直接支持管理动态数组。如果希望使用shared_ptr管理动态数组,必须提供自己定义的删除器:
shared_ptr<int> sp(new int[], [](int *p) {delete[] p; });
sp.reset();//使用lambda释放数组
for (size_t i = ; i != ; ++i)
{
up[i] = i;
*(sp.get() + i) = i;
}
- allocator类
new有一些灵活性上的局限,其中一方面表现在它将内存分配和对象构造组合在一起。类似的,delete将对象析构和内存释放组合在一起;
当分配一大块内存时,我们通常计划在这块内存上按需构造对象。在此情况下,我们希望将内存分配和对象构造分离。这意味着我们可以分配大块内存,但只在真正需要时才执行对象创建工作。
allocator的两个伴随算法:
uninitialized_copy(b, e, b2);//从迭代器b和e指定的范围拷贝元素到迭代器b2指定的未构造的原始内存中。
uninitialized_copy_n(b, n, b2)
uninitialized_fill(b, e, t);//在迭代器b和e指定的原始内存范围内创建对象,值均为t的拷贝;
uninitialized_fill_n(b, n, t)
Chapter12:动态内存的更多相关文章
- Chapter12(动态内存)--C++Prime笔记
1.分配再静态或栈内存中的对象由编译器自动创建销毁. 2.C++中动态内存的管理是通过 new:前者为对象非配空间并返回一个指向该对象的指针. delete:接受一个动态对象的指针,摧毁该对象,并释放 ...
- 【转】Linux C动态内存泄漏追踪方法
原文:http://www.cnblogs.com/san-fu-su/p/5737984.html C里面没有垃圾回收机制,有时候你申请了动态内存却忘记释放,这就尴尬了(你的程序扮演了强盗角色,有借 ...
- C++指针和动态内存分配
指针和动态内存分配 数组与指针 数组 数组名是一个指针常量. 数组名传递数据时,传递的是地址. 数组作为函数参数时不指定第一维大小. 对象数组 A a[2] = {A(1,2)}; 执行时先调用有参数 ...
- SQLite剖析之动态内存分配
SQLite通过动态内存分配来获取各种对象(例如数据库连接和SQL预处理语句)所需内存.建立数据库文件的内存Cache.保存查询结果. 1.特性 SQLite内核和它的内存分配子系统提供以下特性 ...
- C和指针 第十一章 动态内存分配
声明数组时,必须指定数组长度,才可以编译,但是如果需要在运行时,指定数组的长度的话,那么就需要动态的分配内存. C函数库stdlib.h提供了两个函数,malloc和free,分别用于执行动态内存分配 ...
- 解决Ubuntu Server 12.04 在Hyper-v 2012 R2中不能使用动态内存的问题
前言 全新Hyper-v 2012 R2终于开始支持在Linux的VPS中使用动态内存,可以大大优化服务器的资源分配,小弟我兴奋不已,于是抽空时间赶紧升级到 2012 R2,好好整理一番内存分配,不过 ...
- 动态内存分配导致Javascript性能的问题
内存分配对性能的影响是很大的,分配内存本身需要时间,垃圾回收器回收内存也需要时间,所以应该尽量避免在堆里分配内存.不过直到最近优化HoLa cantk时,我才深刻的体会到内存分配对性能的影响,其中有一 ...
- C++动态内存管理之shared_ptr、unique_ptr
C++中的动态内存管理是通过new和delete两个操作符来完成的.new操作符,为对象分配内存并调用对象所属类的构造函数,返回一个指向该对象的指针.delete调用时,销毁对象,并释放对象所在的内存 ...
- 【C++】动态内存与智能指针
C++常见的内存分配方式有三种: 从静态存储区分配,这里主要是存储局部static对象,类的static成员以及定义在函数之外的变量: 从栈内存分配,这里主要是存储函数内的非static对象: 从堆内 ...
随机推荐
- poj 1180 斜率优化dp
这个题目要是顺着dp的话很难做,但是倒着推就很容易退出比较简单的关系式了. dp[i]=min(dp[u]+(sum[u-1]-sum[i-1]+s)*f[i]);dp[i]代表从i到结尾需要花费的代 ...
- DHT11温湿度传感器
一.硬件介绍 RH是相对湿度,是用零点温度来定义的,一般,RH在45%~65%之间最为合适. 注:NTC为热敏电阻,输出为:单总线数字信号,单线双向串行通讯. 注:上拉电阻情况下,配置为开漏输出,可以 ...
- JAVA中的内部类使用总结
1) 内部类的优点是:内部类可以访问外部类的私有成员变量,而不需要new外部类的对象. 2) 内部类又分为:静态内部类.匿名内部类.局部内部类.成员内部类. 3) ...
- js收藏
//设为主页function SetHome(obj, vrl) { try { obj.style.behavior = 'url(#default#homepage)'; obj.setHomeP ...
- 35.3wCF编程
1.新建一个空白的解决方案文件,然后添加新建项目,项目类型为WCF服务应用程序,CH35Ex01 2.添加新建控制台应用程序Ch35Ex01Client 3.生成解决方案 4.右键Ch35Ex01Cl ...
- Git基础(一)
本系列内容主要介绍Git一些基本的也是最常用的命令,相信读完本系列内容后,你也差不多能够上手Git了.读完本系列,你就能初始化一个新的代码仓库,做一些适当配置:开始或停止跟踪某些文件:暂存或提交某些更 ...
- 如何扩展VCL的hint
默认的Hint窗口展现如下: 这种情况下可以操作有窗口的背景颜色,字体样式 Application.Color 有的时候仅仅是文字满足不了我们的需求,比例如下格式: 这个时候就应该执行以下步骤: 1. ...
- [ionic开源项目教程] - 第2讲 新建项目,配置app.js和controllers.js搭建基础视图
新建项目 由项目功能架构图选择合适的页面架构,这里选用Tab,ionic新建项目,默认的模板就是tab. $ ionic start TongeNews Creating Ionic app in f ...
- 基于HtmlUnit的模板的网页数据抽取
既然方向定了,就开始做实验室吧,做舆情分析,首先就是要收集相关的语料 正好实验室有同学在做标化院的信息抽取抽取这块 于是把程序拿过来研究研究正好 完整程序在126邮箱共享: 可下载数:20 共享连接 ...
- HDU 5319 Painter (模拟)
题意: 一个画家画出一张,有3种颜色的笔,R.G.B.R看成'\',B看成'/',G看成这两种的重叠(即叉形).给的是一个矩阵,矩阵中只有4种符号,除了3种颜色还有'.',代表没有涂色.问最小耗费多少 ...