c++的学习之路:8、内存管理与模板

一、 C/C++内存分布

首先在c语言的动态内存管理中我知道了代码是如何存储数据的,然后c++是根据c语言底层变化来的,那么c语言的内存管理就是适用c++的内存管理,在c语言中程序是分为几个部分存储,例如在栈堆等等,他们的分布如下图就是一个分布,有点抽象。

1、栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。

2、 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)

3、堆用于程序运行时动态内存分配,堆是可以上增长的。

4、数据段--存储全局数据和静态数据。

5、代码段--可执行的代码/只读常量。

二、C语言中动态内存管理方式

c语言的内存管理就是利用malloc/calloc/realloc/free,如下方代码所示就是利用这几个函数去管理的,这里就不细说了,在C语言内存管理说的比较详细,这里可以看出malloc申请的空间,realloc是扩容,但是都不进行初始化,这个calloc会初始化,所以可以看出下方图片test2是0。

int main()
{
    int* testptr1 = (int*)malloc(sizeof(int));
    if (testptr1 == nullptr)
    {
        perror("malloc fail");
        return NULL;
    }
    int* testptr2 = (int*)calloc(4, sizeof(int));
    if (testptr2 == nullptr)
    {
        perror("calloc fail");
        return NULL;
    }
    int* testptr3 = (int*)realloc(testptr1, sizeof(int) * 10);
    if (testptr3 == nullptr)
    {
        perror("realloc fail");
        return NULL;
    }
    //free(testptr1);
    free(testptr2);
    free(testptr3);
    return 0;

三、 C++中动态内存管理

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因
此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。如下图代码就是利用new去开辟空间,可以看到代码中,ptr1就是开辟了一个int的空间,ptr2就是开辟了一个int然后并且初始化,delect就是相当于free,注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与
free不会。

void Test()
{
    int* ptr1 = new int;
    int* ptr2 = new int(10);
    int* ptr3 = new int[3];
    delete ptr1;
    delete ptr2;
    delete[] ptr3;
}

四、 operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator  new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。怎么说呢这两个函数其实就是起的函数名叫这个,并不是函数重载这里要分清楚,从下方代码可以看出。

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空               间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)

    if (_callnewh(size) == 0)
    {
        // report no memory
        // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
        static const std::bad_alloc nomem;
        _RAISE(nomem);
    }
return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
    _CrtMemBlockHeader * pHead;
    RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
    if (pUserData == NULL)
        return;
    _mlock(_HEAP_LOCK);  /* block other threads */
    __TRY
        /* get a pointer to memory block header */
        pHead = pHdr(pUserData);
         /* verify block type */
        _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
        _free_dbg( pUserData, pHead->nBlockUse );
    __FINALLY
        _munlock(_HEAP_LOCK);  /* release other threads */
    __END_TRY_FINALLY
    return;
}

五、new和delete的实现原理

1、内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申
请空间失败时会抛异常,malloc会返回NULL。

2、自定义类型new的原理

① 调用operator new函数申请空间

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

delete的原理

① 在空间上执行析构函数,完成对象中资源的清理工作

② 调用operator delete函数释放对象的空间

new T[N]的原理

①调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请

②在申请的空间上执行N次构造函数

delete[]的原理

① 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理

② 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

六、泛型编程

像下方代码这样交换需要使用很多次的时候,每次都要写个对应的交换就会显得很麻烦,如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

void Swap(int& a1, int& a2)
{
    int tmp = a1;
    a1 = a2;
    a2 = tmp;
}

void Swap(double& a1, double& a2)
{
    double tmp = a1;
    a1 = a2;
    a2 = tmp;
}

int main()
{
    int a1 = 10, a2 = 20;
    double b1 = 11.11, b2 = 22.22;
    Swap(a1, a2);
    Swap(b1, b2);
    return 0;
}

七、函数模板

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

他的格式如下,编写的测试代码如下,这里也是可以class

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

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

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

1. 隐式实例化:让编译器根据实参推演模板参数的实际类型 

2. 显式实例化:在函数名后的<>中指定模板参数的实际类型

如同下方代码就是利用显式实例化,因为两个不同的类型就没有找到对应的实例化,所以这里就是用了显式实例化,结果如图。

template<typename T>
T Add(const T& a1, const T& a2)
{
    return a1 + a2;
}

int main()
{
    int a1 = 10, a2 = 20;
    double b1 = 11.11, b2 = 22.22;
    cout << Add(a1, a2) << endl;
    cout << Add(b1, b2) << endl;
    cout << Add<int>(a1, b2) << endl;
    cout << Add<double>(b1, a2) << endl;
    return 0;
}

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

八、类模板

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

类模版格式代码如下

template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
public :
Vector(size_t capacity = 10)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
// 使用析构函数演示:在类中声明,在类外定义。
~Vector();
void PushBack(const T& data);
void PopBack();
// ...
size_t Size() {return _size;}
T& operator[](size_t pos)
{
assert(pos < _size);
return _pData[pos];
}
private:
T* _pData;
size_t _size;
size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
if(_pData)
delete[] _pData;
_size = _capacity = 0;
}

相关推荐

  1. C++内存管理模型

    2024-04-03 06:56:04       59 阅读
  2. C++——内存管理模板

    2024-04-03 06:56:04       42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-03 06:56:04       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-03 06:56:04       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-03 06:56:04       87 阅读
  4. Python语言-面向对象

    2024-04-03 06:56:04       96 阅读

热门阅读

  1. 王道c语言-选择排序

    2024-04-03 06:56:04       37 阅读
  2. QT 支持window 和 mac下应用程序崩溃检测

    2024-04-03 06:56:04       40 阅读
  3. 自动化标准Makefile与lds

    2024-04-03 06:56:04       40 阅读
  4. ActiViz中的数据集vtkPolyData

    2024-04-03 06:56:04       50 阅读
  5. 数据库设计规范(三大范式)

    2024-04-03 06:56:04       41 阅读
  6. 第八章:k8s如何使用 Service 暴露你的应用

    2024-04-03 06:56:04       37 阅读