从入门到了解C++系列-----内存管理 + 初步了解模板
目录
前言
1.c/c++ 的内存分布
2. c++ 中内存管理方式
2.1 有什么
2.2 怎么用
2.2.1 new
2.2.2 delete
2.2.3 operator new 与 operator delete
2.3 内存泄露
2.3.1 是什么
2.3.2 检测内存泄漏
3. 模板
3.1 是什么
3.2 怎么用
3.3 深入了解模板
3.4 类模板
3.4.1 深入分析类模板
结尾:
前言
本篇文章是对于 c++中内存管理的讲解。将会讲解两个部分:一个是数据的存储,另外一个是new 与 delete。也是对于我学习内容的总结与分析。
1.c/c++ 的内存分布
请看下面一段代码,分析其中的代码数据分别是存放在什么区域。
int gloabval = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
首先1.globalvar 是一个全局变量,存放在 c 静态区里面。第二个为 c, staticVar是静态变量存放在栈上 C,local 是局部变量存放在栈,num1 数组名存放在栈上 A。char2 数组名存放在栈上 A。*char 相当于是对首元素的地址进行解引用,但是数组内容还是存放在栈上。pchar3 指针变量名存放在栈上,为 A。*pchar3 是 a 存放在代码段上 D。ptr1是 int 型指针的名字,所以是存放在栈,但是 *ptr1是malloc 开辟的空间,存放在堆上 B。
答案为:C C C A A A A A D A B (从左向右,从上到下)
下面一道题是计算所占空间的大小。
sizeof 于 strlen 的区别在于 sizeof 是取到 '\0' 为止,而strlen是就是字符串的长度,其次sizeof是运算符,而strlen是函数。指针的所占字节就是 4 、8个。
2. c++ 中内存管理方式
2.1 有什么
在c++中重新定义了 new 于 delete,来进行实现动态内存的开辟。
2.2 怎么用
2.2.1 new
int* a = new int;//注意返回值的类型为指针类型
int* b = new int[10];//这是开辟10个空间
int* c = new int(10);//这是开辟了一个空间,将里面的内容初始化为了 10
int* d = (int*)malloc(sizeof(int));
new的基本使用如上,它的这种使用方法与 malloc 没有区别。但是对于自定义类型(类)就有很大的区别。
new可以自动调用构造于析构函数,但是 malloc 不可以。
class Stack
{
public:
Stack()
{
_a = 0;
cout<< "Stack()" << endl;
}
private:
int _a;
int _b;
}
int main()
{
Stack* a = new Stack;
Stack* b = (Stack*)malloc(sizeof(Stack));
}
2.2.2 delete
delete就是释放,动态内存开辟的空间(以上面的代码为例)
//释放开辟好的一个空间
delete a;
//释放开辟好的好几个空间
delete[] b;
同样的道理,delete与free最大的区别在于,在delets在清除的时候会调用析构函数(不只是类,跟准确来说是自定义类型)。而free不可以,我就不写代码了。
2.2.3 operator new 与 operator delete
new 与 delete 是操作符,而 operator new 与 operator delete 是系统提供的全局函数,new 与 delete 的底层也是调用的这两个函数。
然而 operator new / delete,在实现的时候使用的是 malloc 与 free。而最大的区别在于 operator new/delete 在失败的时候会抛异常。他的代码实现如下,对于我现在的水平来说实现有点复杂。
2.2.4 总结
1.new = operator new + 构造函数。 delete = operator delete + 析构函数。
2. operator new = malloc + 抛异常。 operator = free + 抛异常。
常见的面试题目:区分malloc 与 new 的相同点与不同点(free 与 delete 类似):
相同点:都是在堆上进行空间的开辟与释放。并且需要进行手动的释放。 、
不同点:1. 就是 new 比 malloc 多了一个构造函数(针对于自定义类型) + 没有生成成功的话会抛异常。
2. new 是操作符,而 malloc 与 free是函数。
3. malloc 在生成空间时需要手动输入所占的字节大小,而 new 只需要加上需要开辟的空间的类型即可,如果是想要开辟多个空间的话[n],直接这样写就可以。
4. malloc 返回的时 void* 类型的地址,需要进行强制转化,但是 new 不需要。
2.3 内存泄露
2.3.1 是什么
内存的泄露是指由于 malloc 与 new 开辟可空间但是没有进行释放,导致内存空间的浪费。开辟空间是在堆上开辟的空间,由于堆的内存空间大小是非常有限的,与代码区、硬盘不是一个级别,会很容易造成浪费。
2.3.2 检测内存泄漏
这一部分的内容不进行详细的解释,了解即可。在这里我推荐给大家几个进行检测内存泄漏的工具。
1.在linux下内存泄漏检测:Linux下几款C++程序中的内存泄露检查工具_c++内存泄露工具分析-CSDN博客
2.在windows下使用第三方工具:VS编程内存泄漏:VLD(Visual LeakDetector)内存泄露库_visual leak detector vs2020-CSDN博客
3.其他工具:内存泄露检测工具比较 - 默默淡然 - 博客园
3. 模板
3.1 是什么
简单来说,模板就相当于是一个懒人工具,使用模板时会自动来调用对应的类型,自动实现相应转化。需要注意的是如果我们不调用模板函数的话,就不会编译相应的内容,也就是说不用的情况下,有错误也不会报错。有时也称之为范式编程。
3.2 怎么用
template<class T> //也可以将里面的内容替换为: typename T
T add(T &a,T &b)// 如果是返回值的话是需要返回的类型为 T
{
return a + b;
}
int main()
{
int a = 1, b = 2;
int c = add(a, b);
cout<< c << endl;
double a1 = 1.1, b1 = 2.2;
double c1 = add(a1, b1);
cout<< c1 << endl;
}
代码的使用如上所示。
3.3 深入了解模板
那模板是为了解决什么问题呢?c ++ 跟 c 的不同又是在哪里,c++做了一些什么?让我带着这些问题来进行下面的解释。
如果我们想要同时实现不同数据类型的 Stack,以及不希望里面的内容进行改变、同时还希望不用自己手动去调用析构函数自动实现内存的释放,为了解决这些问题,C++ 里面的类 + 模板就很好的解决了这样的问题。
3.4 类模板
前面介绍的是函数模板实现不同类型的函数,此小节是模板函数的另外一个分类为:类的模板。
以栈为例子进行分析。代码如下:
template<class T>
class Vector
{
public:
//栈的初始化
Vector(size_t capacity = 0)
:a(new T[capacity])
, size_t capacity(capacity)
, size_t size(0)
{
}
//栈析构函数
~Vector()
{ }
//尾插
void Push_Back(const T& x);
//尾删
void Pop_Back();
//返回长度大小, 类内定义,类内实现
size_t Size()
{
return _size;
}
//[] 函数的重载,找到 pos 位置所对应的代码
T& operator[](size_t pos)
{
assert(pos >= size && pos <= capacity);
return a[pos];
}
private:
T* a;
size_t capacity;
size_t size;
};
// 类内定义,类外实现
template<class T>
void Vector<T>::Push_Back(const T& x);
template<class T>
Vector<T>::~Vector()
{
if (a)
{
delete[] a;
}
capacity = size = 0;
}
int mian()
{
Vector<int> s;//定义 int 类型的s
Vector<double> s1;//定义 double 类型的 s1;
}
3.4.1 深入分析类模板
不要小看内存泄漏问题,我们创建一个栈,开辟完一个空间之后很容易忘记进行销毁空间。类两个函数就很好的解决了这种问题。 同时也解决了外部不可以修改内容的问题。
4. 结尾:
如果对你有帮助还请帮我点个免费的赞,支持一下我,我也会不断地改进争取写出跟高质量的文章。我们共同努力!!!!😊😊😊