内存管理+模板

  • 内存管理
    • C
    • C++
    • 内置类型
    • 自定义类型
    • 内存泄漏
  • 模板
    • 泛型编程
    • 函数模板
      • 模板参数匹配原则
    • 类模板

内存管理

C

malloc();
free();

C++

new
delete

内置类型

对于C++和C中而言,如果操作的对象是内置类型,
new/mallocdelete/free基本没什么区别

new/delete操作的是单个元素空间
new[]/delete[]操作的是连续空间

自定义类型

new/new[]和delete/delete[]实际上是调用 operator 重载函数

new的原理

  1. 调用operator new函数申请空间

  2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理

  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间

new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申
  2. 在申请的空间上执行N次构造函数

delete[]的原理

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

malloc/freenew/delete
共同点是:都是从堆上申请空间,并且需要用户手动释放。

不同的地方是

  1. malloc和free是函数,new和delete是操作符
  2. malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间 后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

内存泄漏

进行内存管理的时候要小心内存泄漏

内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。
内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

内存泄漏的危害

长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

提问:内存泄漏是指针丢失还是内存丢失

答:指针丢失。
内存泄漏是无法操作那块内存空间,无法再通过指针操作内存空间。而内存一直是在那块空间中。比如,指针指向0x00bbff80就是那块空间的地址,当指针丢失,我们不知道空间的地址的多少,但那块空间的实际地址依然是0x00bbff80,其空间地址不会因为指针丢失而改变位置。

模板

泛型编程

C++提供了模板来处理很多问题
介绍一个概念:泛型编程

就是通过模板来解决问题,如:swap交换

C++可以通过函数重载来交换几个类型的数据,但依旧是效率太低,而且,可维护性太差,如果一个函数有误,那所有都需要整改。

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}
void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}

函数模板

所以引入了函数模板的概念:允许以泛型(任意类型)的方式来定义函数
格式:

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}


如:交换函数

template<typename T>
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}

或者

template<class T>
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}

我更推荐用关键字class
这个就是泛型编程。我提供一个模板,当使用时,会根据接受参数的类型完成函数功能。

模板就是图纸,可以根据各种需求来完成功能。
举个例子

#include<iostream>
using namespace std;
template <class T>
void swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}
int main(void)
{int i1 = 10, i2 = 100;double d1 = 10.0, d2 = 100.0;swap(i1, i2);swap(d1, d2);return 0;
}

提问:当这个swap()函数被调用了,是调用了同一个函数,还是不同的函数?

答:不同的函数

理由:

这是查了汇编代码,当调用两个函数时,call两个函数的地址是不一样的,所以明显是调用了两个不同的函数

这就涉及到另一个概念:函数模板的实例化

简单来说就是通过一张图纸来建造不同样子的房子
以上面程序为例,函数模板就是图纸,当调用函数的时候就是建造不同的房子,所以就是调用了不同的函数。

隐式实例化:编译器会根据参数的类型,自动推断类型,然后去创建函数的实力化。

 swap(i1, i2);swap(d1, d2);

显式实例化:不需要编译器去推断,显式指定类型。

 swap<int>(i1, i2);swap<double>(d1, d2);

当然,还有要是不确定两个类型是否相同,但还是能转换。
为了这个比较没啥用,还无意义的要求

#include<iostream>
using namespace std;
template <class T1,class T2>
void Swap(T1& a, T2& b)
{T1 tmp = a;a = b;b = (T2)tmp;
}
int main(void)
{int i1 = 10, i2 = 400;double d1 = 10.0, d2 = 100.0;cout << i1 << " " << d2 << endl;Swap(i1, d2);cout << i1 << " " << d2 << endl;Swap(d1, d2);return 0;
}

不同类型数据交换会造成数据丢失,没什么用。
范围小的数据类型会截断范围大的数据类型的数据,会造成数据丢失。

对于一些加法,减法运算,对于类型未知,可以这样编写。

#include<iostream>
using namespace std;template <class T3, class T4>
auto Add(T3 a, T4 b)
{return a + b;
}
int main(void)
{int i1 = 10, i2 = 400;double d1 = 10.2, d2 = 20.3798; auto ret = Add(i1, d2);cout<<ret<<endl;return 0;
}

auto会自己推断返回值的类型。
当然,肯定是范围小的数据类型会升级为范围大的数据类型。

模板参数匹配原则

  1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函模板还可以被实例化为这个非模板函数
  2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
  3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

例子:

int Add(int left, int right)
{return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{return left + right;
}
void Test()
{Add(1, 2); // 与非模板函数匹配,编译器不需要特化Add<int>(1, 2); // 调用编译器特化的Add版本Add(1,2.0);//模板函数会生成更加匹配的版本,会调用模板函数
}

类模板

类模板和类又有些区别。
这才是他们之间的关系。

类模板:未知类型的类

举个例子:

template <class T>
class vector
{public:typedef T* iterator;typedef const T* const_iterator;vector():_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){}vector(const vector<T>& vt)//允许没有<T>:_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){size_t Capacity = vt.capacity();this->reserve(Capacity);for (auto e : vt){push_back(e);}}~vector(){if (_start){delete[] _start;}_start = _finish = _end_of_storage = nullptr;}vector<T>& operator= (const vector<T>& x){if (this != &x){vector<T> tmp(x);    this->swap(tmp);}return *this;}T& operator[](size_t pos){assert(pos < _size);return _start[pos];}private:iterator _start;iterator _finish;iterator _end_of_storage;};

这是我迷你实现过的vector类模板(只给你们看一部分)。
在使用过程中,类模板会根据类的类型来实例化成相应类型的类

vector<int>
vector<double>
vector<string>

这些才是类,类模板是不知道类型的。

注意:类模板中函数放在类外进行定义时,需要加模板参数列表

template <class T>
vector<T>::~vector()
{if (_start){delete[] _start;}_start = _finish = _end_of_storage = nullptr;
}

模板初阶大概就这些东西,谢谢观看。
对于C++入门知识点不清楚的,请移步

C++入门知识点

系统学习C++的类与对象

C++内存管理+模板入门知识点相关推荐

  1. FineReport帆软报错:很抱歉,数据集行数过多触发保护机制,请减少查询数据量。若您是管理员,可于智能运维-内存管理-模板限制中更改此项限制。

    使用帆软时候,数据集记录数过多时候,FineReport帆软报错,如下: 很抱歉,数据集行数过多触发保护机制,请减少查询数据量.若您是管理员,可于智能运维-内存管理-模板限制中更改此项限制. 如下图所 ...

  2. C/C++内存管理模板初阶

    内存管理和模板初阶 1 内存管理 1.1 C/C++ 的内存分布 1.2 C 中动态内存管理方式 1.3 C++ 中动态内存管理方式 1.3.1 new/delete操作内置类型 1.3.2 new/ ...

  3. 【Bugly干货分享】iOS内存管理:从MRC到ARC实践

    本文作者:王拥军 腾讯自选股高级开发工程师 Bugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly 邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创. 对于i ...

  4. iOS开发——MRC(手动内存管理)

    iOS开发--MRC(手动内存管理) 内存分配区域 栈区 堆区 总结 常量区 总结 代码区 总结 全局区 关于如何查看一个对象在堆区 / 栈区 需要知道的知识 手动引用计数MRC 四个法则 非自己生成 ...

  5. 从底层原理出发,了解Linux内核之内存管理

    本文讲解更加底层,基本都是从Linux内核出发,会更深入.所以当你都读完,然后再次审视这些功能的实现和设计时,我相信你会有种豁然开朗的感觉. 1.页 内核把物理页作为内存管理的基本单元. 尽管处理器的 ...

  6. 学习笔记:C++初阶【C++入门、类和对象、C/C++内存管理、模板初阶、STL简介、string、vector、list、stack、queueu、模板进阶、C++的IO流】

    文章目录 前言 一.C++入门 1. C++关键字 2.命名空间 2.1 C语言缺点之一,没办法很好地解决命名冲突问题 2.2 C++提出了一个新语法--命名空间 2.2.1 命名空间概念 2.2.2 ...

  7. python终结一个循环额_Python语言入门之内存管理方式和垃圾回收算法解析

    本文主要向大家介绍了Python语言入门之内存管理方式和垃圾回收算法解析,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助. 在列表,元组,实例,类,字典和函数中存在循环引用问题.有 ...

  8. spark从入门到精通spark内存管理详解- 堆内堆外内存管理

    前言 Spark作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解Spark内存管理的基本原理,有助于更好地开发Spark应用程序和进行性能调优.本文将详细介绍两部 ...

  9. 内存编程 c语言 c,C语言编程入门之内存管理

    本篇教程探讨了C语言编程入门之内存管理,希望阅读本篇文章以后大家有所收获,帮助大家对相关内容的理解更加深入. < 自动变量与静态变量 auto自动变量 auto是默认的关键字,如实际中int a ...

最新文章

  1. python flask高级编程之restful_('Python Flask高级编程之RESTFul API前后端分离精讲',),全套视频教程学习资料通过百度云网盘下载...
  2. 从零实现一个简易jQuery框架之一—jQuery框架概述
  3. Git远程分支的回退
  4. 浅谈jQuery的选择器
  5. python 生成器装饰器_4.python迭代器生成器装饰器
  6. nginx升级修复(CVE-2016-4450)
  7. 手动创建Oracle实例
  8. Matplotlib常用命令
  9. tkinter事件机制
  10. 联合国应考虑建设第二总部
  11. kgtemp文件转mp3工具
  12. android程序设计学习,android编程入门很简单 android编程入门自学
  13. 图像融合算法及多视角(多源)信息融合总结
  14. 关于MPU6050学习的一些总结之一MPU6050芯片手册的整理
  15. Git 版本控制系统的安装与使用
  16. centos6如何配置ip
  17. java校园快递代领系统 小程序
  18. 什么是计算机网络的组成和功能是什么,计算机网络的组成要素及功能是什么
  19. excle中数字太大,显示不全
  20. 数学建模——评价算法

热门文章

  1. 新媒体人必看!如何利用飞项做好内容运营管理
  2. 纯 CSS 实现蜡烛融化(水滴)效果
  3. WinDebug 配置 调试 设置
  4. [FROM WOJ]#1935 魔法树
  5. Linux 18 IPC之共享内存shm
  6. es6 babel转码器安装配置
  7. 安全技术基础知识科普
  8. android屏幕解锁新解
  9. 【实验七】【使用规则实现数据完整性】
  10. 工具集合-脚本合并(Groovy)