当前位置: 首页 > wzjs >正文

网站建设维护app怎么推广

网站建设维护,app怎么推广,网络服务主要包括哪些方面,crm客户端文章目录1、内存分布2、动态内存管理2.1 C中的动态内存管理2.2 C中的内存管理2.3 new和delete操作自定义类型2.4 new和delete的底层实现2.6 new和delete的实现原理2.7 定位new表达式的使用3、初识模板3.1 函数模板3.2 类模板1、内存分布 注意的是: 栈区是向低地址(…

文章目录

    • 1、内存分布
    • 2、动态内存管理
      • 2.1 C中的动态内存管理
      • 2.2 C++中的内存管理
      • 2.3 new和delete操作自定义类型
      • 2.4 new和delete的底层实现
      • 2.6 new和delete的实现原理
      • 2.7 定位new表达式的使用
    • 3、初识模板
      • 3.1 函数模板
      • 3.2 类模板

1、内存分布

在这里插入图片描述

注意的是:

  1. 栈区是向低地址(向下增长)开辟,堆区是向高地址(向上赠长)开辟。
  2. 未初始化的或初始化为0的变量(静态和全局的)存放在BSS段,未初始化的局部变量存放在栈区。
  3. 初始化的变量(静态和全局的)存放在数据段(也称为静态区)。
  4. 代码段(也称为常量区)存放程序编译后的汇编代码以及常量。
  5. 堆区只能动态开辟,栈区既可以静态开辟也可以动态开辟(_alloc函数)。

2、动态内存管理

2.1 C中的动态内存管理

在之前C语言中,我们一般用malloc函数进行动态内存开辟。
一般都有的步骤是 调用函数动态开辟、判断返回值、释放空间。

int* a = (int*)malloc(sizeof(int));
if(a == NULL)
{perror("malloc fail");exit(-1);
}
free(a);

2.2 C++中的内存管理

C中的内存管理在C++中也能继续使用。

C++规定通过一个new操作符来动态开辟空间,通过delete操作符来释放空间。

//动态申请一块int大小的空间
int* p1 = new int;//动态申请一块int大小的空间并初始化
int* p2 = new int(10);//动态申请多块int大小的空间并初始化
int* p3 = new int[10]{0};//释放空间
delete p1;
delete p2;//对多块空间释放,需要加[],[]内可以不写具体数字
delete[] p3;

注意new和delete操作符匹配,new[]和delete[] 操作符匹配。


那C++的动态开辟和C语言的动态开辟有什么区别呢?
下面我们继续探讨

2.3 new和delete操作自定义类型

先弄一个类A

#include <iostream>
using std::cout;
using std::endl;class A
{
public:A(int a = 1):_a(a){cout << "A(int a = 1)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};int main()
{A* a1 = (A*)malloc(sizeof(A));free(a1);cout << "-----" << endl;A* p1 = new A(1);delete p1;return 0;
}

在这里插入图片描述
首先可以明显的看到,new/delete和malloc/free的一个很大区别就是,对于类类型new/delete会调用构造函数和析构函数。
实际上:

  1. 对于内置类型,new/delete和malloc/free几乎一样。
  2. 对于自定义类型,new开了空间后还会调用构造函数,delete调用析构函数后会释放空间。

2.4 new和delete的底层实现

new的底层实现
下面是官方实现的operator new函数,从中大概来看,其实new的底层就是malloc,只是多个当申请失败会抛异常(这里先知道会抛异常,不用知道是什么)。

这里值得注意的是,operator new只是一个库里面实现的全局函数,并不是new的操作符重载,因为参数里面没有自定义类型。(这是一个对新手的误区,以为是操作符重载)

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0) //malloc返回null就进入循环if (_callnewh(size) == 0){// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}
return (p);
}

从底层代码我们可以了解new开辟失败返回异常,我们再来看看new开辟失败p1还会像malloc一样返回null指针吗。

#include<iostream>
using namespace std;
void Test1()
{while (1){//循环每次开辟空间 看看当开辟失败的时候p1返回是否为空char* p1 = new char[1024*1024*1024];if (p1 == nullptr){perror("malloc fail");exit(-1);}}
}int main()
{try{Test1();}catch (exception& e){cout << e.what() << endl;}return 0;
}

在这里插入图片描述

从输出结果来看,并不会返回空指针,并且只抛异常输出异常结果。(这里我们先不讨论异常以后会谈滴)

delete底层实现
这里我们只需要知道,delete的底层代码调用了free()函数来释放空间。

#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)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_FINALLYreturn;
}

总结:

  • new的底层实现是通过malloc,只不过多了抛异常。
  • delete的底层说明最终是通过free函数来释放空间的。

2.6 new和delete的实现原理

对于内置类型
new/delete和malloc/free基本一致,不同的是new开辟空间失败会抛异常,而malloc开辟失败返回NULL指针。

对于自定义类型
我们现在已经知道了

  • new的实现原理

    1.调用operator new 函数申请空间
    2.在申请的空间上执行构造函数

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


那么new[] 和 delete[] 的原理是什么样的?

  • new[] 的实现原理

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

  • delete[] 的实现原理

    1.调用operator delete[] 函数,实际调用operator delete函数完成空间的释放,而operator delete 实际也是通过free完成释放。
    2.先会多次调用析构函数,完成多个对象空间的资源清理

2.7 定位new表达式的使用

new是先开空间,再调用构造函数初始化。
定位new是在已分配原始内存空间中调用构造函数初始化一个对象。

使用方式:
new(place_address)type 或者 new(place_address)type(initializer-list)
place_address是一个指针,initializer-list是类型初始化列表。

class A
{
public:A(int a = 0):_a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}private:int _a;
};int main()
{A* p1 = (A*)malloc(sizeof(A));if (p1 == nullptr){perror("malloc fail");exit(-1);}new(p1)A(1);p1->~A();free(p1);A* p2 = (A*)operator new(sizeof(A));new(p2)A(1);p2->~A();operator delete(p2);return 0;
}

在这里插入图片描述

定位new在实际中一般是配合内存池进行使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。


接下来我们就可以总结一下malloc和new的区别

  1. malloc是函数,new是操作符。。
  2. malloc在开多个空间需要计算大小,new只需要填写数字就行。
  3. malloc返回值是void*需要强转,new只需要声明类型。
  4. malloc开辟失败返回空指针,new开辟失败抛异常。
  5. malloc只开空间不初始化,new即开空间又调用构造函数初始化。
  6. malloc相匹配释放空间的free只释放空间,new相匹配的delete不仅释放空间还调用析构函数。


3、初识模板

3.1 函数模板

当我们面对同一个函数需要处理多个类型的情况时,函数模板可以给我们提供很大的便利。

函数模板的格式
template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}

typename是用来定义模板参数关键字,也可以使用class。

用法:

template<typename T>
void Swap(T& left, T& right)
{T temp = left;left = right;right = temp;
}int main()
{int a = 1, b = 2;Swap(a, b);double c = 1.1, d = 2.2;Swap(c, d);cout << a << " " << b << endl;cout << c << " " << d << endl;return 0;
}

值得注意的是,上面Swap函数是一个模板(一个蓝图),本身并没有实例化,只有当我们调用的时候编译器会根据参数类型自动推演实例化一个函数。

我们知道编译器会根据参数类型进行推演,那么当参数类型不同会发生什么呢

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}int main()
{int a1 = 10, a2 = 20;double d1 = 10.1, d2 = 20.2;//自动推演//cout << Add(a1, d1) << endl; //编译报错cout << Add(a1, a2) << endl;cout << Add(d1, d2) << endl;//强转可以运行,不过强转生成临时变量具有常性,函数需要加constcout << Add((double)a1, d2) << endl;cout << Add(a1, (int)d2) << endl;//显示实例化//这种写法可以指定类型//a1 到double类型 有隐式类型转换会产生临时变量具有常性 需要加constcout << Add<double>(a1, d2) << endl;cout << Add<int>(a1, d2) << endl;return 0;
}

参数不一致第一种处理方法就是强转或者指定类型

//这样写两个不同类型就能直接相加
template<class T1, typename T2>
T1 Add(const T1& left, const T2& right)
{return left + right;
}int main()
{int a1 = 10, a2 = 20;double d1 = 10.1, d2 = 20.2;cout << Add(a1, a2) << endl;cout << Add(d1, d2) << endl;cout << Add(a1, d2) << endl;cout << Add(d1, a2) << endl;return 0;
}

参数不一致第二种处理方法就是添加两个类型


当我们写了的函数能用的话,编译器也不会再生成,只有指定调通用的才会推演生成。

int Add(int left, int right)
{return left + right;
}template<class T>
T Add(T left, T right)
{return left + right;
}int main()
{int a = 1, b = 2;Add(a, b);//调专门的不调通用的Add<int>(a, b); //要调通用的编译器自己推演return 0;
}


3.2 类模板

类模板的定义格式:
template<class T1, class T2, …, class Tn>
class 类模板名
{
// 类内成员定义
};

例子:

template<typename T>
class Stack
{
public:Stack(int capacity = 4){cout << "Stack(int capacity = )" <<capacity<<endl;_a = (T*)malloc(sizeof(T)*capacity);if (_a == nullptr){perror("malloc fail");exit(-1);}_top = 0;_capacity = capacity;}~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;}void Push(const T& x){// ....// 扩容_a[_top++] = x;}private:T* _a;int _top;int _capacity;
};int main()
{//类型是Stack<double> st1使得类实例化Stack<double> st1;st1.Push(1.1);//类型是Stack<int> st2使得类实例化Stack<int> st2;st2.Push(1);return 0;
}

类模板不是真正的类,只有当实例化后才是类。
由于类的实例化一开始不会传参,所以类模板没有推演时机。
虽然是同一个类模板实力化的,但是参数不同,类型不同,大小不一样。

并且类模板中成员函数的定义与声明最好写在同一文件中

如果定义与声明分离,由于类模板未实例化问题,会发生链接错误。
如果一定要声明与定义分离,需要在每个包含类模板的文件实例化(这就很麻烦,所以尽量避免声明与定义分离)。

头文件中实例化写法

//stack<int>类实例化
template
class stack<int>;

本章完~

http://www.dtcms.com/wzjs/99840.html

相关文章:

  • 陕西交通建设网站链接交换公司
  • 可以做网络攻防的实验的网站友情链接如何交换
  • 合肥百度 网站建设推广产品的方法和步骤
  • 长沙网站开发方案青岛官网seo公司
  • 重庆专业网站搭建公司seo排名系统
  • 做运营那些无版权图片网站百度公司官网
  • 攀枝花网站推广百度导航下载2022最新版
  • 营销型网站建设易网拓搜索引擎优化的根本目的
  • 自己做的网站怎么在百度可以查到湛江今日头条新闻
  • 广东省住房及建设厅官方网站千锋教育学费
  • 济南h5网站建设旅游营销推广方案
  • 沈阳seo哪家公司东莞网站seo公司哪家大
  • 站长工具查询视频网络营销是什么专业类别
  • 做行业分析的网站公司企业网站制作
  • 济宁建设局网站首页北京谷歌优化
  • 网站建设微信官网开发台州seo优化公司
  • 0592 网站建设网站首页模板
  • 做调查赚钱靠谱的网站seo精华网站
  • 皮卡剧网站怎样做永久免费建站系统
  • 如皋做网站的公司互联网营销师是做什么的
  • 做企业网站设计价格是多少钱产品推广方式及推广计划
  • 绛帐做企业网站西安seo计费管理
  • 做怎个样网做站个网站seo优化技术培训
  • 濮阳建站公司哪个好深圳网站开发公司
  • 自己电脑做网站服务器系统广州seo优化
  • 重庆新闻联播今天百度首页排名优化服务
  • 自己做网站要哪些东西销售推广方案
  • 南宁网站建设电话seo网站分析报告
  • 网站备案什么注销百度品牌广告多少钱一个月
  • 广州力科网站建设公司重庆网站制作公司哪家好