智能指针

This commit is contained in:
estomm
2021-03-06 18:24:08 +08:00
parent 76df1f7708
commit 662c870902
34 changed files with 500 additions and 48 deletions

View File

@@ -0,0 +1,136 @@
# 动态内存
## 0 C++直接管理内存
### 概念
* C++使用new分配内存使用delete释放new分配的内存。
* 动态对象的声明周期从创建到被释放时为止。
### 使用动态内存的原因
> 既然这么多风险为什么要使用动态内存
1. 程序不知道自己需要使用给多少对象。动态循环创建多个对象。容器包括字符串string都是使用动态内存管理自身的存储。
2. 程序不知道所需对象的准确类型。运行过程中创建对象。
3. 程序需要在多个对象间共享数据。多个对象共享相同的状态。
### 申请内存
* new无法围棋分配的对象命名而是返回一个指向该对象的指针。
```
int * p = new int;
```
* 动态分配的对象执行默认初始化操作。内置类型和组合类型的对象是未定义的。类类型的对象使用默认构造函数进行初始化。
* 可以动态分配const对象
```
const int * pci = new const int(1024);
```
* 内存耗尽后new表达式会失败。抛出bad_alloc异常。
### 释放内存
* 使用delete来释放内存。将动态内存归还给系统。
* delete指针必须指向动态分配的内存或一个空指针。
* 释放一块非new分配的内存或者将相同的指针释放多次行为是未定义。产生错误。
* delete对象之后指针指向的地址被释放了指针无效。但是指针依旧保存着原先的地址。编程**悬空指针**。
## 1 动态内存与智能指针
> 所以智能指针使用过来做动态内存管理的。普通的局部变量及其指针不需要智能指针。智能指针是辅助new delete来管理动态内存的。智能指针就是为了解决一下问题。
### 两个问题
指针直接管理内存存在两个问题:
1. 没有释放内存,导致内存泄露。
2. 访问已经释放的内存,引起引用非法内存的指针。
### 智能指针
* share_ptr 允许多个指针指向同一对象
* unique_ptr 独占所指向的对象
* weak_ptr伴随类。弱引用。指向shared_ptr所管理的对象。
### 头文件
```
#include<memory>
```
### 智能指针的基础操作
![](2021-03-06-17-05-19.png)
## 2 动态内存管理shared_ptr
### shared_ptr的操作
![](2021-03-06-17-06-13.png)
### make_shared申请内存
* 最安全的使用动态内存的方法调用make_shared标准库函数。在动态内存中分配一个对象并初始化。返回shared_ptr.
```
shared_ptr<int> pn = make_shared<int>(42);
auto = make_shared<int>(42);
```
### shared_ptr拷贝和引用计数
* shared_ptr 都有一个关联的计数器。引用计数。每次copy一个shared_ptr计数器都会递增。例如将它作为参数传递给一个函数或者作为函数的返回值。
* 一旦一个shared_ptr的计数器变为0.它就会自动释放自己所管理的内存。使用析构函数,销毁自身。
* 所以当它为局部变量,并且退出局部作用域后,所有的指针变量自动销毁,其所对应的动态分配的内存对象的引用计数就回变为零,此时动态内存会自动销毁。
![](2021-03-06-17-26-40.png)
### shared_ptr和new申请内存
* shared_ptr可以使用make_shared创建对象。也可以使用new返回的指针来初始化智能指针。此时不需要delete来释放。
```
share_ptr<int> p2(new int(42));
```
### shared_ptr的其他方法
![](2021-03-06-17-43-51.png)
## 3 动态内存管理 unique_ptr
![](2021-03-06-17-58-42.png)
* unique_ptr是弱化的shared_ptr。某个时刻只能有一个unique_ptr直线跟一个给定的对象。当unique_ptr被销毁时它所指向的对象也被销毁。
* unique_ptr需要绑定到一个new返回的指针上。直接将指针置为空指针指向的对象就会被释放。可以使用delete释放unique_ptr
* unique_ptr不支持普通的拷贝和赋值操作。但是可以考别或赋值一个将要被销毁的unique_ptr.例如return unique_ptr。实现控制权转移
```
unique_ptr<int> clone(int p){
return unique_ptr<int>(new int(p));
}//返回了一个动态内存的unique_ptr
```
* 可以release放弃控制权把控制权移交给新的智能指针。实现动态内存的控制权转移。
```
unique_ptr<int> m=new int;
unique_ptr<int> n = m.release();//m放弃所有权转移给n
```
## 4 动态内存管理weak_ptr
* 不控制所指向对象生存期的智能指针。它指向一个由shared_ptr管理的对象。
* 将weak_ptr绑定到shared_ptr上不会改变shared_ptr的引用计数。当shared_ptr被销毁对象就回被释放。
![](2021-03-06-18-09-20.png)
* 使用shared_ptr初始化weak_ptr
```
shared_ptr<int> p = make_shared<int>(42);
weak_ptr<int>wp(p);
```
* 由于weak_ptr指向的对象可能不存在使用lock检查weak_ptr指向的对象是否存在。
```
if(shared_ptr<int>np = wp.lock()){
}
```
## 4 动态数组
## 5 文本查询程序

12
C++/标准库/12.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include<iostream>
#include<memory>
using namespace std;
int main(){
//最安全的分配和使用广东台内存的方法,
shared_ptr<int> p1 = make_shared<int>(42);
shared_ptr<int> p2(new int(42));
unique_ptr<string> p1(new string("stego"));
return 0;
}

View File

@@ -12,8 +12,15 @@
4. 头尾插入元素使用deque
5. 可以在输入阶段随机插入的时候使用list然后将复制好的放到vector中加速访问。
### C++ STL容器的实现
## 2 容器的基础操作
![](2021-03-06-15-39-37.png)
### C++ STL容器概览
![](2021-03-06-15-41-19.png)
## 2 所有容器的基础操作
### 容器统一的操作
![](2021-03-05-20-17-45.png)
@@ -27,6 +34,7 @@
![](2021-03-05-20-29-29.png)
### 容器大小的操作
* size():返回容器中元素的数目
@@ -40,44 +48,7 @@
* 除了无序关联容器,都支持关系运算(> < >= <=)
* 必须是相同各类型的容器,且元素类型相同才能比较。
## 3 顺序容器的操作
### 向顺序容器中添加元素
![](2021-03-05-20-37-12.png)
* 在尾部添加元素push_back()
* 在头部添加元素push_front()
* 在中间添加元素insert()
### 在顺序容器中访问元素
![](2021-03-05-20-40-51.png)
* 也可以使用迭代器访问元素。
* at会进行安全检查抛出异常。[]不会进行检查。
### 在顺序容器中删除元素
![](2021-03-05-20-42-30.png)
> 操作记忆
> * back、front、push_back、push_front、pop_back、pop_front。是一组首尾相关的操作。
> * insert、at、erase。是一组随机的操作。
### foward_list的特殊操作
![](2021-03-05-20-54-47.png)
### 改变容器的大小
![](2021-03-05-20-56-47.png)
## 4 容器的容量问题
## 3 容器的容量问题
### vector的存储

View File

@@ -8,6 +8,40 @@
> * forward_list
> * string//专门用于字符串访问的容器
## 0 顺序容器的基础操作
### 向顺序容器中添加元素
![](2021-03-05-20-37-12.png)
* 在尾部添加元素push_back()
* 在头部添加元素push_front()
* 在中间添加元素insert()
### 在顺序容器中访问元素
![](2021-03-05-20-40-51.png)
* 也可以使用迭代器访问元素。
* at会进行安全检查抛出异常。[]不会进行检查。
### 在顺序容器中删除元素
![](2021-03-05-20-42-30.png)
> 操作记忆
> * back、front、push_back、push_front、pop_back、pop_front。是一组首尾相关的操作。
> * insert、at、erase。是一组随机的操作。
### foward_list的特殊操作
![](2021-03-05-20-54-47.png)
### 改变容器的大小
![](2021-03-05-20-56-47.png)
## 1 array

View File

@@ -0,0 +1,156 @@
# 关联容器
## 1 关联容器概述
### 关联容器与顺序容器的区别
关联容器和顺序容器有着根本不同。关联容器中的元素是按关键字来把偶才能和访问的。书序容器中的元素是按他们在容器中的位置来顺序保存和访问的。
### 两个基础类型
* map:键值对key-value。关键字是索引值表示与索引相关的数据。
* set:每个元素只包含一个关键字。支持高校的关键字查询操作。
### 关联容器之间的区别
* 是一个set或者map
* 要求不重复的关键字,允许重复的关键字。
* 按顺序保存元素。无序保存。
![](2021-03-06-15-48-08.png)
### 关联容器的头文件
* `<map>`:map,multimap
* `<set>`:set,multiset
* `<unorder_map>`:unorder_map,unorder_multimap
* `<unorder_set>`:unorder_set,unorder_multiset
### map和set的使用
```
#include<iostream>
#include<map>
#include<set>
using namespace std;
int main(){
map<string,int> word_count;
string word="hello";
word_count[word]=10;
word_count["world"]=35;
//遍历map
for(auto &w:word_count){
cout<<"w.first"<<w.second<<endl;
}
//set
set<string> ss{"yin","kang","long","hello","world"};
for (auto s : ss)
{
cout<<s<<endl;
}
return 0;
}
```
### 定义关联容器
* map、set的定义和初始化
```
map<string,int> word_count;//空容器
set<string> ex{"the","to"};//初始化set
map<string,int> wc{
{"jo",10},
{"yin",13},
{"kang",53},
{"long",3}
};//初始化map
```
* multimap、multiset的定义和初始化。允许关键字的重复。
```
//可以使用顺序容器初始化关联容器multiset初始化
vector<int> vec{1,2,3,4,5,5,4,3,2,1};
set<int> iset(vec.begin(),vec.end());
multiset<int> mset(vec.begin(),vec.end());
cout<<iset.size()<<endl;
cout<<mset.size()<<endl;
```
### pair类型
* 类似容器pair是用来生成特定类型的模板。
* 定义pair
```
pair<string,string> author{'James","joyce"};
```
* pair上的操作
![](2021-03-06-16-18-21.png)
## 2 关联容器的基础操作
### 关联容器额外的类型名
![](2021-03-06-16-20-49.png)
### 关联容器的迭代器和元素遍历
```
//使用迭代器遍历关联容器
auto map_it = word_count.cbegin();
while(map_it != word_count.cend()){
cout<<map_it->first<<map_it->second<<endl;
map_it++;
}
```
### 关联容器的算法
* 我们通常不对关联容器使用泛型算法
### 添加元素
![](2021-03-06-16-32-02.png)
### 删除元素
![](2021-03-06-16-32-39.png)
### map下标操作
![](2021-03-06-16-33-47.png)
### 访问元素
![](2021-03-06-16-34-40.png)
## 3 无序关联容器的基础操作
### 说明
* 不适用比较运算符来组织元素,使用哈希函数和关键字类型的==运算符。
* 使用无序容器通常更简单,具有更好的效果。
### 基础操作
* 与有序容器一样包括find、insert
### 管理桶
* 无序关联容器相对于普通关联容器的特殊操作。
![](2021-03-06-16-48-05.png)

59
C++/标准库/2.2.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include<iostream>
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<vector>
using namespace std;
int main(){
map<string,int> word_count;//空容器
set<string> ex{"the","to"};//初始化set
map<string,int> wc{
{"jo",10},
{"yin",13},
{"kang",53},
{"long",3}
};//初始化map
string word="hello";
word_count[word]=10;
word_count["world"]=35;
//遍历map
for(auto &w:word_count){
cout<<"w.first"<<w.second<<endl;
}
//set
set<string> ss{"yin","kang","long","hello","world"};
for (auto s : ss)
{
cout<<s<<endl;
}
//可以使用顺序容器初始化关联容器multiset初始化
vector<int> vec{1,2,3,4,5,5,4,3,2,1};
set<int> iset(vec.begin(),vec.end());
multiset<int> mset(vec.begin(),vec.end());
cout<<iset.size()<<endl;
cout<<mset.size()<<endl;
//使用迭代器遍历关联容器
auto map_it = word_count.cbegin();
while(map_it != word_count.cend()){
cout<<map_it->first<<map_it->second<<endl;
map_it++;
}
//无序map测试
unordered_map<string,int> people;
people["yin"]=10;
people["yin"]++;
cout<<people["yin"]<<endl;
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

View File

@@ -91,7 +91,7 @@ int main(){
* istream_iterator:读取输入流
* istream_iterator:读取输入流。可以为任何定义了输入运算符的类创建迭代器对象。
![](2021-03-06-14-50-48.png)
@@ -117,7 +117,18 @@ int main(){
cout<<*str_it<<endl;
```
* ostream_iterator:读取输出流
* ostream_iterator:读取输出流。可以为任何创建了输出运算符的类,创建输出流迭代器。
![](2021-03-06-14-51-10.png)
![](2021-03-06-14-51-10.png)
```
ostream_iterator<int> out_iter(cout,"\n");
*out_iter =10;
*out_iter = 100;
```
### 反向迭代器
从容器的尾元素向首元素反向移动的迭代器。递增递减操作相反。

View File

@@ -34,5 +34,8 @@ int main(){
str_it++;
cout<<*str_it<<endl;
ostream_iterator<int> out_iter(cout,"\n");
*out_iter =10;
*out_iter = 100;
return 0;
}

View File

@@ -1,7 +1,7 @@
# 算法
## 1 算法概览
## 1 泛型算法概览
### 头文件
#include<algorithm>//标准库算法
@@ -18,7 +18,7 @@
* 只读算法。不改变元素的值
* 更易算法。该表容器的元素
### 示例
### 常用算法示例
* 只读算法
accumulate()
@@ -45,5 +45,66 @@ find()
find_if()
## 2
## 2 泛型算法的结构
### 五类迭代器
泛型算法只要能够提供五个迭代器类别,所有到的泛型算法都能够执行。每个算法都会对他的每个迭代器指明提供哪类迭代器。
![](2021-03-06-15-13-07.png)
### 输入迭代器
* 可以读取序列中的元素
* 比较两个迭代器的运算符==!=
* 推进迭代器前置或后置的递增运算符++
* 用于读取元素的解引用运算符* ->
### 输出迭代器
* 可以向序列中写入元素
* 用于推进迭代器前置和后置的递增运算
* 用于写入的解引用运算符。只能是左值。
### 前向迭代器
* 只能沿一个方向运动
### 双向迭代器
* 可以正反两个方向运动。支持++和--
### 随机访问迭代器
* 常量时间内随机访问序列中任意元素的能力。下标访问。
* 用于比较迭代器相对位置的关系运算符< > <= >=,基于随机访问能力。
* 迭代器和一个整数值的加减运算 + += - -=
* 用于计算迭代器距离的运算符-。基于随机访问能力
* 下标运算符[]。提供随机访问能力
### 算法的形参模式
* 必然是一下四中形式之一
* 接受单个目标迭代器的算法
* 接受第二个输入序列的算法
![](2021-03-06-15-23-17.png)
### 算法的命名规范
* 算法有多个重载版本
* _if结尾多加一个**谓词**。可以传递一个函数。
* _copy结尾表示多加一个序列用来拷贝结果。
## 3 特定容器算法
### list和forward_list的特定算法
* 成员函数中的算法
![](2021-03-06-15-27-21.png)
* splice算法
![](2021-03-06-15-28-46.png)

0
C++/标准库/5.cpp Normal file
View File

0
C++/标准库/6.cpp Normal file
View File

View File

@@ -0,0 +1,9 @@
# 动态内存
## 1 C中动态内存的实现
## 2 C++中动态内存的实现
## 3 两者的区别和优势劣势

View File

@@ -8,7 +8,7 @@
### 工作
- 制作简历(明天)
- 知识复习——语言
- 知识复习——语言(一周)
- C++primer
- 基础语法√
- 标准库 STL
@@ -18,10 +18,10 @@
- 系列视频
- 问题专项解决)
- Java语法、标准库
- 知识复习——算法
- 知识复习——算法(一周)
- 数据结构
- 算法
- 知识复习——基础
- 知识复习——基础(一周)
- 计算机网络
- 数据库
- 操作系统