C++内存和管理模板

#include<iostream>
using namespace std;
class Stack
{
public:
	Stack(int capacity = 4)
	{
		cout << "Stack(int capacity = 4)" << endl;
		_a = new int[capacity];
		_top = 0;
		_capacity = capacity;
	}
	~Stack()
	{
		cout << "~Stack()" << endl;
		delete[] _a;
		_a = nullptr;
		_top = 0;
		_capacity = 0;
	}
private:
	int* _a;
	int  _top;
	int  _capacity;
};
  1. new 是C++的一个关键字,它的用途是开辟空间,并且调用构造函数;在1这里,new开辟了一个Stack类型的空间大小,同时调用它的构造函数Stack(int capacity=4)进行初始化;这里Stack的空间大小为12个字节,因为它的成员有1个int*类型,和2个int类型大小的成员,所以是12个字节,因此开辟12个字节的空间;
    delete也是C++的一个关键字,它的用途有调用析构函数,同时释放对象空间,归还操作系统;
    这里delete会调用析构函数,并且释放空间,但是注意,这里的析构如果没有先把_a指向的数组先给delete释放掉,然后才delete释放p1指向的Stack对象的空间,会导致程序直接错误,原因是一旦Stack空间全部被释放,而_a指向的数组没被释放,会导致_a就变成野指针,从而导致内存泄漏,泄漏原因是_a指向的数组还没有被释放,同时空间并没有归还操作系统。
    这里要注意new开空间开的是对象的空间,delete释放的是对象的空间
class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};

但在A对象却不存在上述的问题。原因是A对象虽然是自定义类型,但其只有一个int类型的成员_a。
2.接着说操作符operator new 和operator delete的用途,其实它俩就和C语言的malloc和free函数的用途一模一样,之所以在C++中要写成这种形式,是因为C++是面向对象的高级语言,大众需要看懂它们的意思,malloc和free函数开辟和释放空间失败后返回的是数字,但让别人看很难懂其中的意思,这时候operator new和operator delete就发挥了作用,它俩其实就是包装了malloc和free,它俩开辟和释放空间失败后就是处理失败抛异常问题,这里就不过的赘述;new开辟空间就是进行operator new 操作,delete释放空间就是进行operator delete;但唯一区别就是如果失败了,它们返回的东西能不能让人一下就看懂;

这里是是用new开辟一个连续的空间存放数组
在这里插入图片描述
看图的右侧,最上面一行0a 00 00 00,这是系统自动开辟的一个空间,是一个计数的变量,用来记录析构数组元素的个数,接下来每一个框起来的部分就是一个Stack对象的所有成员地址。
这里有需要注意的地方,delete[]p3不能写成delete p3,一旦写错程序就报错,因为p3指向的是数组的第一个元素,而不是系统自动开辟空间存放的变量的那个地址,如图所示,所以一旦delete后,然后释放空间,就会报错,因为系统开辟的空间并没有全部释放。

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}
/*	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
*/
};

但如果是这样的类型在一些编译器下是可以通过的,因为只有_a是内置类型,系统认为析不析构没有意义,就不析构了,所以不会开辟最前面的4个字节的空间用来计数,因此就可以直接释放空间了。
所以new/delete new[]/delete[] malloc/free 需要配对使用才不会出错;
3.如果需要频繁的用new去申请一些小空间,这时候就可以通过内存池来进行空间的存储。
我先举一个简单的例子先让大家大概理解一下:大学生每个月都需要问家里要生活费,如果家里有一个大学生,每天都问家里要当天的生活费,每天都要给他转钱,短时间内还能接受,时间一长就会觉得很烦;如果家里有三个大学生都这样,那估计都能累炸,所以干脆一次性给他们每个人转一个月的生活费,这样就很省事了,如果有些节俭的直接可以给一学期的生活费,那就更省事了,如果花完了再给就行了。通过这个例子,我可以知道内存池大概是干啥的了。从系统那里申请一些空间存放在内存池,如果有需要内存的直接就从内存池里拿,不需要再让操作系统安排了,如果用完了接着再向操作系统申请。但是内存池中申请的对象中的数据没有初始化,所以需要用定位new显示调用构造函数初始化对象

int main()
{
	构造函数自动调用
       A aa1;

	// A* p2 = new A(1);

   A* p1 = (A*)operator new(sizeof(A));

	// 不能这么显示调用构造函数
	//p1->A(1);
	// 但是可以用定位new显示调用构造函数
	new(p1)A(1);

	// 析构函数可以显示调用
	p1->~A();
	operator delete(p1);

4.模板
一.

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 T>
template<class T>

这两种形式都可以

void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

这三个函数就可以改成这一种写法,在主函数中调用;

int main(){
	int a = 0, b = 1;
	double c = 1.1, d = 2.2// 调用是不是同一个函数
	Swap(a, b);
	Swap(c, d);
	}

模板参数语法 很类似函数参数,函数参数定义的形参对象,模板参数定义的是类型。模板下面就必须挨着调用的函数,不然就没用了;一个模板就对应一个调用的函数。

模板有两种实例化,推演实例化和显示实例化。

template<class X, class Y>
void func(const X& x, const Y& y)
{
	cout << x << y << endl;
}
  //推演实例化
  //函数参数传递,推出模板参数的类型,生成对应的函数
  int main(){
   func(1, 2);
   func(1.1, 2.2);
   func(1.1, 2);
  }
template<class T>
T Add(T left, T right)
{
	return left + right;
}
  int main(){
	cout << Add(1, (int)2.2) << endl;
   	// 显式实例化
	cout << Add<int>(1, 2.2) << endl;
	cout << Add<double> (1, 2.2) << endl;
	}

这里Add( 1 , 2.2 )既有int也有float,所以传过去是错误的,可以直接将两种类型变成一种类型,也可以在Add后面加int,进行显示实例化,这样系统就会将2.2强转为int类型,同时也会认为T是int

template<class T>
T* f(int n)
{
	T* p = new T[n];
	return p;
}
 int main(){
 double* p = f<double>(10);
 }

这里必须要显示实例化,10是int类型传递给int n没问题,但是T是什么类型就不知道了,这里T跟形参没有任何关系。

如果我有什么错误希望大家多多指教,如果喜欢就希望大家多多支持,谢谢!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值