==========================================================================
day08
==========================================================================
1. map又称为关联数组。

使用map来写单词计数程序

E1: map<string, size_t> word_count;
string word;
while (cin >> word) {
++word_count[word]; // map中的下标操作符[],如果word不在map中,则下标操作符会添加一个新元素.所以[]只可以用在非const的map
// 有时候我们只想知道一个元素是否在map中,但在不存在时并不想添加元素,就不能使用下标操作符
}
for (const auto &w : word_count)
cout << w.first << " occurs " << w.second << ((w.second > 1) ? "times" : "time")<<endl;

E2: map<string, size_t> word_count;
string word;
while (cin >> word) {
auto ret = word_count.insert({word,1}); // 插入一个元素,关键字为word,值为1.如果map中已存在,则什么都不做
if (!ret.second) // word 已在map中
++ret.first->second; // 递增计数器
}
for (const auto &w : word_count)
cout << w.first << " occurs " << w.second << ((w.second > 1) ? "times" : "time") << endl;

2.动态内存管理

#include<memory>

为了更容易更安全的使用动态内存,标准库提供了两种智能指针类型来管理动态对象。
shared_ptr 允许多个指针指向同一个对象 用法: shared_ptr<string> // 表示指针可以指向的类型为string
unique_ptr 独占所指的对象

标准库还定义了weak_ptr,是一种弱引用,指向shared_ptr所管理的对象

3.内存耗尽。 尽管一般内存足够,但还是可能出现内存耗尽的情况。当内存耗尽,new就会失败,默认情况下,就会抛出一个bad_alloc的异常。
我们可以在出现这种情况时阻止抛出异常,并返回一个空指针: int *p = new (nothrow) int; //如果分配失败,返回一个空指针
这种形式的new称为定位new(placement new) bad_alloc和nothrow都定义在#include<new>中

4.我们传递给delete的指针必须是指向动态分配的内存,或者是一个空指针(nullptr)
eg: int i,*pi1 = &i,*pi2 = nullptr;
double *pd = new double(33),*pd2 = pd;
delete i; //错误,i不是一个指针
delete pi1; //未定义的行为,pi1指向的是一个局部变量 编译器并不会报错
delete pi2; //正确,释放一个空指针总是没错的
delete pd; //正确
delete pd2; //未定义的行为,pd2指向的内存以及被释放过了 编译器并不会报错

delete之后重置指针值:
当我们delete一个指针后,指针值就变得无效了。虽然指针无效了,但在许多机器上指针仍然保存着(已经释放了的)动态内存的地址。在delete之后
指针就变成了悬空指针,即指向一块曾经保存数据但现在已经无效的内存的指针。
避免悬空指针的方法是,delete后,将指针置为nullptr。
但这也仅仅是有限的保护:当多个指针指向相同的内存,delete内存后重置指针为空的方法只对这个指针有效,对其他仍指向(已释放的)内存的指针是没有
作用的。
eg: int *p = new int(42);
autp q = p; // q和p指向相同的内存
delete p; // p和q均变为无效
p = nullptr; // 指出p不再绑定任何对象 但重置p对q没有任何作用,q还是个悬空指针。

5. 注意,内置类型的动态内存分配,需要显式地初始化 : int *p = new int(5); // 初始化为5
否则,其指向的值是未定义的。 而一些内置类或自定义有默认构造函数的类型,如果不显式初始化就会进行默认初始化。

6. make_shared函数类似于容器的emplace()函数(考虑insert与emplace的区别),make_shared用其参数来构造给定类型的对象。
例如,make_shared<string>时传递的参数必须与string的某个构造函数相匹配。
make_shered<string>(10,'a'); 如果什么参数都不传递,则对象进行值初始化。

7.智能指针与new的混用
如果我们不初始化一个智能指针,他就会被初始化为一个空指针。 shared_ptr<int> sp; // 空指针
除了使用make_shared函数初始化智能指针,我们还可以用new返回的指针来初始化智能指针。
shared_ptr<int> p(new int(42)); // 正确,可以使用直接初始化的形式
shared_ptr<int> p1 = new int(1024); // 错误,智能指针的构造函数是explicit的,不能将内置指针隐式转换为智能指针,必须使用直接初始化的形式

【不要将智能指针与普通指针混用】
考虑如下:
void process(shared_ptr<int> ptr)
{
//使用ptr
} // ptr离开作用域,被销毁

上述函数的参数是以传值方式传递的,因此实参会被拷贝到ptr中。拷贝一个shared_ptr会递增其引用计数。因此process运行过程中,引用计数至少为2

shared_ptr<int> p(new int(42)); // 引用计数为1
process(p); // 拷贝p递增它的引用计数; 变为2
int i = *p; // 出了process函数,局部变量ptr被销毁,引用计数变为1,所以仍然可以使用p指向的这块内存

再考虑如下:
int *x(new int(1024));
process(shared_ptr<int>(x)); // 引用计数为1
int j = *x; // 未定义的行为,x变为了空悬指针。
上述调用,我们把一个临时的shared_ptr传给了process,当调用结束,这个临时对象就被销毁了,引用计数就会递减,变为0,因此,临时对象被销毁,
它所指的内存被释放,但x继续指向已经被释放的内存,从而成了一个空悬指针。

所以,使用一个内置指针访问一个智能指针所负责的对象是危险的, 因为我们无法知道对象何时被销毁。

8.之前一直以为野指针和空悬指针一个意思,但错了。
空悬指针(dangling pointer):指向已经销毁的对象或已经回收的地址。
野指针:没有初始化的指针就是野指针。 如:int *p;

9.永远不要用get函数初始化另一个智能指针或为智能指针赋值。
get函数,p.get() ,返回p中保存的指针,返回的是一个内置指针。
get函数是为这样一种情况设计的:我们需要向不能使用智能指针的代码传递一个内置指针。

要非常注意的一点是:get返回的指针,不能用delete

shared_ptr<int> p(new int(42));p指向
int *q = p.get();
....
delete q; // 未定义的行为,因为智能指针p会自动释放内存,而再调用delete q 就会造成了二次释放内存。

10. 因为shared_ptr可能有多个指向了同一块内存,在改变指向的底层对象之前,我们先检查自己是不是当前对象仅有的用户,
如果不是,在改变之前要制作一份新的拷贝。 用到reset函数,其中一种的参数是一个内置指针。(reset函数有三种)
用法:p.reset(q); 令p指向q

if(!p.unique())
p.reset(new string(*p)); // 我们不是唯一用户,分配新的拷贝。
*p += newVal; //现在我们是唯一用户了,可以改变对象的值。

C++Primer笔记-----day08的更多相关文章

  1. C++ Primer笔记

    C++ Primer笔记 ch2 变量和基本类型 声明 extern int i; extern int i = 3.14;//定义 左值引用(绑定零一变量初始值,别名) 不能定义引用的引用:引用必须 ...

  2. C++ Primer 笔记(1)基础中的战斗机 输入输出 对输入不定数据处理

    今天打算再重新好好的看一遍C++ Primer这本很经典的书籍,笔记开始: 1.每个C++程序都包含一个或者多个函数,其中必须有一个main,操作系统通过调用main入手运行程序: 2.函数包括:返回 ...

  3. C++ Primer 笔记 第一章

    C++ Primer 学习笔记 第一章 快速入门 1.1 main函数 系统通过调用main函数来执行程序,并通过main函数的返回值确定程序是否成功执行完毕.通常返回0值表明程序成功执行完毕: ma ...

  4. C++primer笔记之顺序容器

    最近又重新拾起C++primer,发现每一次看都会有不同的体验,但每一次看后因为不常用,忘记得很快,所以记笔记是很关键的一环,咋一看是浪费时间,实际上是节省了很多时间.下面就把这一节的内容做一个简单的 ...

  5. c++ primer 笔记 (一)

    昨天开始看的<C++ Primer>,确实不错.希望这周抓紧看完,每天做下笔记,以便以后复习. main函数返回一个值给操作系统   操作系统通过main函数返回的值来确定程序是否成功执行 ...

  6. C++ Primer笔记(1)——连续读取数据、类型对应的尺寸、类型转换、字符串分行写法

    这次要看看C++ Primer,这本基本上就是必读书籍了.下面的内容就是一些之前没有学过的知识的笔记. 读取数量不定的输入数据 虽然很简单,但是还是记一下: #include <iostream ...

  7. C++Primer笔记(3)

    标准库类型string表示可变长的字符序列,使用前先包含string头文件.(哈哈,终于可以逃脱C语言中的str函数系列了.)因为是标准库的一部分,所以string被定义在命名空间std中.所以你懂该 ...

  8. C++ Primer 笔记 第三章

    C++ Primer 第三章 标准库类型 3.1using声明 例: using namespace atd; using std::cin; 3.2string类型 初始化方式 string s1 ...

  9. C++ Primer 笔记 第二章

    C++ Primer 第二章 变量和基本类型 2.1基本内置类型 有算数类型和void类型:算数类型储存空间大小依及其而定. 算数类型表: 类型 含义 最小储存空间 bool 布尔型 - char 字 ...

随机推荐

  1. TCC(Tiny C Compiler)介绍

    TCC是一个超小.超快的标准C语言编译器.她可以从这里(http://bellard.org/tcc/)下载到:注意,要下载http://download.savannah.nongnu.org/re ...

  2. Charles :mac上的手机代理

    能在手机访问电脑上的网页. 配置: 下载 Charles,选中 Proxy => macOS Proxy Proxy => Proxy Setting 配置上端口 手机无线手动代理,配置上 ...

  3. Jenkins进阶-Gitlab使用Webhook实现Push代码自动部署(3)

    1.Jenkins 安装完成以后,首先我们在Jenkins中需要安装一下,Gitlab Hook Plugin 插件: 2.插件安装完成我们创建任务,在任务重构建触发器下获取回调URL: 注意: 注意 ...

  4. nginx信号量

    nginx信号说明相关说明 信号名称 作用 TERM,INT 快速关闭 QUIT 从容关闭 HUP 重新加载配置,用新的配置开始新的工作进程,从容关闭旧的工作进程 USR1 重新打开日志文件 USR2 ...

  5. ML(2): 术语及算法分类汇总

    机器学习术语 归纳总结机器学习相关的基本术语,以一批西瓜的数据为例,例如:(色泽=青绿:根蒂=蜷缩:敲声=浊响),(色泽=乌黑:根蒂=稍蜷:敲声=沉闷),(色泽=浅白:根蒂=硬挺:敲声=清脆)... ...

  6. 【jmeter】Jmeter进行分布式性能测试

    由于Jmeter本身的瓶颈,当需要模拟数以千计的并发用户时,使用单台机器模拟所有的并发用户就有些力不从心,甚至还会引起JAVA内存溢出的错误.要解决这个问题,可以使用分布式测试,运行多台机器运行所谓的 ...

  7. ASP.NET中将数据作为XML数据发送 使用 Request.InputStream 接收

    将数据作为XML数据发送,例如:public void PostXml(string url, string xml){byte[] bytes = Encoding.UTF8.GetBytes(xm ...

  8. mysql 按照 where in 排序

    select * from user_extend where `unique` in('mark.liu@xxxx.com','jason.gan@xxxx.com','ssgao@xxxx.com ...

  9. [UE4]混合动画以及Try Get Pawn Owner、Get Velocity、VectorLength的使用

    混合动画,可以混合个多动画之间的动画,多个动画相当于关键帧,关键帧之间可以生成混合出过度动画. 实时动态更新Speed参数. 知识点: 一.可以在蓝图中使用“Try Get Pawn Owner”取得 ...

  10. IP地址与子网掩码

    IP地址 众所周知,为了确保通信时能相互识别,在internet上的每台主机都必须有一个唯一的标识,即主机的IP地址.IP协议就是根据IP地址来实现信息传递的. IP地址由32位(4字节)二进制数组成 ...