C++函数模板与内存管理详解

简介: C++函数模板与内存管理详解

情景引入:

现在假设我们要写一个swap函数交换两个值的大小,我们知道在之前讲过的函数重载是支持不同类型的参数重载的,因此我们只要写出int ,double ,char ,float ,bool的类型函数重载就行了,但是这个函数的功能差距不大,就因为类型不同我们就要写这么多,这显然不划算,因此C++里面提出了一种方法,支持模糊的类型匹配————模板



一:模板

我们前面知道模板支持模糊匹配,但是这并不代表模板的类型匹配不严格,相反模板里面是不允许类型的隐式转化(除非显示标注类型),从某种意义上来说,模板的类型匹配更加严格,那这是什么情况呢?看起来我们确实利用函数模板偷懒了很多,其实真正意义上并没有偷懒,只是我们偷的懒被系统做了而已。我们先看下面这个模板

template<class A,typename B>//类模板的定义
void swap(A& a,B& b){
A temp=a;             
a=b;
b=temp;
}          出了作用域若想要再次使用模板就需要重新定义,
            模板只管模板定义处的下一行或者下一个作用域

那么编译器到底是怎么帮我们偷懒的呢?在我们没有使用这个函数的时候是并没有这个函数的,当我们使用的时候编译器通过对类型的辨认如何形成这个函数,在通过这个函数去进行操作。

现在有这么一个函数的模板

template<typename B>
void swap(B& a,B& b){
B temp=a;             
a=b;
b=temp;
}

如果我们传一个这个参数过去会怎么样呢?

int a=1;
double b=0.0;
swap(a,b);

编译器会帮我们成功的交换吗?事实是编译器会报错,这是因为只有一个模板却有两个类型,有些情况就是这样的那我们怎么办呢?当然有办法,那就是使用的时候显示指定类型,如下

int a=1;
double b=0.0;
swap<int>(a,b);
swap<double>(a,b);

二:内存管理

1)内存分布

在C++中内存大概可以分为五块

向下生长的栈空间:栈是用来储存局部变量和函数的空间,因为使用的时候,地址是越来越小,所以称为向下生长,因为这一块空间用完了它就会向比它地址低的空间去申请,并且栈只支持静态增长。

向上生长的堆:堆是支持动态增长的,像malloc,calloc,realloc,new的空间都是在这里开辟的,这里的空间直到程序结束才会释放,因此需要我们手动释放开辟的空间,但要注意释放空间不能多次释放。使用这里的空间地址是越来越大的,因为这一块空间用完了它就会向比它地址高的空间去申请

内存映射段:内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。

数据段:存储全局数据和静态数据

代码段:存储可执行代码和只读常量

2)new和delete

在C++中new和delete是类似与C里面的malloc和realloc还有calloc的开辟空间的手段

区别:new和delete是内置基本操作符,malloc等是函数,

new=开辟空间+调用构造函数

delete=调用析构函数+释放空间

malloc=开辟空间

free=释放空间

new,malloc,delete,free能混着用吗?

答案:不能,因为可能会造成内存泄漏,new的类里面可能还有在堆上开辟的空间,如果不调用析构函数释放会造成内存泄漏

有些人就要问了,为什么有了malloc和realloc和calloc还有发明new?

那我们想象一下,我们创建了一个类,我们使用malloc的方式给它开辟空间,我们该如果给它初始化呢?

这就暴露的malloc等的一个大弊端,malloc,calloc是无法给自定义类型初始化的,new应运而生,new支持对自定义类型的初始化。我们看代码,里面有从基本内置类型到类的new空间基本操作

int* a=new int;//只开辟空间,不初始化
int* a=new int(6);//给a开辟空间并且初始化为6
delete a;//释放空间
int* a=new int[6];//给a开辟一个数组大小为6
int* a=new int[6]{1,2,3,4,5,6};//给a开辟一个数组大小为6,并且全部赋值
int* a=new int[6];//数组里面全是随机值
int* a=new int[6]{};//数组里面全是0
delete[] a; //释放空间
Date a=new Date{2023,11,11};//日期类并且赋初值
delete a;释放空间
Date a[3]=new Date[3]{(2023,11,11),(2024,11,11),(2025,11,11)};//自定义类型数组赋初值
delete[] a;

看到上面,你有没有想为什么数组释放空间需要[],这个真的毫无用处吗?

错,首先我们想一下,编译器是如何判断这个数组有多大的空间,如果是你你会怎么做?编译器在开辟空间会多开四个字节,正好一个int大小,这个int用来储存数组的数量,通过这个int我们就可以准确的释放数组空间,这个int类型一般在开辟空间的前面,这样就可以快速准确拿到数组大小,释放空间,如果我们不使用[]这个,那么空间就会从中间被释放,导致报错。

3)简单介绍new和delete底层原理。

在new和delete的底层原理其实就是调用了被封装的malloc和free,malloc被封装在new的函数重载里面,free被封装在delete的函数重载里面,为什么要封装呢?这是因为malloc分配空间出错是直接返回0,而C++的要求的抛错,为了达到这个效果,必需封装一下malloc和free,并且不要忘记new里面会调用构造函数delete里面会调用析构函数。new的函数重载只负责开辟空间,delete的函数重载只负责释放空间,调用析构函数和构造函数还是在new运算符里面。

new=malloc+调用构造函数

delete=free+释放空间

malloc=开辟空间

free=释放空间

相关文章
【硬核】C++11并发:内存模型和原子类型
本文从C++11并发编程中的关键概念——内存模型与原子类型入手,结合详尽的代码示例,抽丝剥茧地介绍了如何实现无锁化并发的性能优化。
什么是内存泄漏?C++中如何检测和解决?
大家好,我是V哥。内存泄露是编程中的常见问题,可能导致程序崩溃。特别是在金三银四跳槽季,面试官常问此问题。本文将探讨内存泄露的定义、危害、检测方法及解决策略,帮助你掌握这一关键知识点。通过学习如何正确管理内存、使用智能指针和RAII原则,避免内存泄露,提升代码健壮性。同时,了解常见的内存泄露场景,如忘记释放内存、异常处理不当等,确保在面试中不被秒杀。最后,预祝大家新的一年工作顺利,涨薪多多!关注威哥爱编程,一起成为更好的程序员。
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
72 6
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
81 4
【C++】模板详细讲解(含反向迭代器)
C++模板是泛型编程的核心,允许编写与类型无关的代码,提高代码复用性和灵活性。模板分为函数模板和类模板,支持隐式和显式实例化,以及特化(全特化和偏特化)。C++标准库广泛使用模板,如容器、迭代器、算法和函数对象等,以支持高效、灵活的编程。反向迭代器通过对正向迭代器的封装,实现了逆序遍历的功能。
39 3
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
64 3
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
192 4
|
2月前
|
【c++】模板详解(1)
本文介绍了C++中的模板概念,包括函数模板和类模板,强调了模板作为泛型编程基础的重要性。函数模板允许创建类型无关的函数,类模板则能根据不同的类型生成不同的类。文章通过具体示例详细解释了模板的定义、实例化及匹配原则,帮助读者理解模板机制,为学习STL打下基础。
39 0
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
【C++打怪之路Lv7】-- 模板初阶
【C++打怪之路Lv7】-- 模板初阶
28 1
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等