目录
定位new表达式
定位new使用的池化技术:
编辑
malloc和free与new和delete的区别:
内存泄漏:
模板
显示实例化
两个不同参数的模板
模板函数与函数:
类模板
[]重载:
定位new表达式
class A
{
public:A(int a=0):_a(a){cout << "构造函数" << this << endl;}~A(){cout << "析构函数" << endl;}
private:int _a;
};int main()
{A*p1 = new A;//A*p2 = new A[10];A*p3 = (A*)malloc(sizeof(A));if (p3 == nullptr){perror("malloc fail");exit(-1);}new(p3)A(1);return 0;
}
使用场景:
已分配地址。
对对象完成初始化。
我们要完成释放:
也可以直接使用delete函数。
定位new使用的池化技术:
当我们要使用栈上的空间时,我们每一次使用堆空间都需要申请,我们可以建立一个内存池,该内存池有一部分内存,我们可以直接使用。
对于这类可以不申请就可以使用的空间(内存池)
我们需要通过定位new来完成初始化
malloc和free与new和delete的区别:
内存泄漏:
内存泄漏:指针丢了
指针丢了,我们就无法通过该指针释放对应空间,造成内存泄漏。
模板
#include<iostream>
using namespace std;
void Swap(int&a, int&b)
{int tmp = a;a = b;b - tmp;
}
void Swap(double&a, double&b)
{double tmp = a;a = b;b - tmp;
}
int main()
{int a = 1, b = 2;Swap(a, b);double x = 1.1, y = 2.2;Swap(x, y);return 0;
}
我们实现的两个函数功能相同,只是处理的变量类型不同,我们必须显示的定义出两个函数。
有没有办法可以只定义出一个函数实现以上操作呢?
#include<iostream>
using namespace std;
template <typename T>//void Swap(int&a, int&b)
//{
// int tmp = a;
// a = b;
// b - tmp;
//}
//void Swap(double&a, double&b)
//{
// double tmp = a;
// a = b;
// b - tmp;
//}
void Swap(T&a, T&b)
{T tmp = a;a = b;b = tmp;
}
int main()
{int a = 1, b = 2;Swap(a, b);double x = 1.1, y = 2.2;Swap(x, y);return 0;
}
我们只用了一个函数就实现了多种类型的交换。
Swap函数调用的是我们的函数模板吗?
答:并不是,我们定义的模板可以根据调用参数的类型来实例化出不同的重载函数:
所以我们实例化函数并不是所有的函数都实例化,我们的实例化是对所调用函数的参数进行比对来进行实例化,我们调用几种不同类型的函数,就实例化几个函数。
实例化是编译器帮助完成的。
假如我们调用不同参数类型的交换函数,会怎么样呢?
int main()
{int a = 1, b = 2;Swap(a, b);double x = 1.1, y = 2.2;Swap(x, y);Swap(a, x);return 0;
}
这里并不能发生强制类型转换,类型转换发生在赋值或者传参之间,这里是实例化期间。
template<class T>
T Add(const T&left, const T&right)
{return left + right;
}
int main()
{int a = 1, b = 2;double c = 1.1, d = 2.2;/*cout << Add(a, b) << endl;cout << Add(c,d) << endl;*/cout << Add(a, c) << endl;return 0;
}
我们用const修饰了,传参时应该可以类型转换,为什么还会报错?
因为我们的模板函数的两个参数都是T,是相同的,所以我们无法调用使用两个不同参数的函数,我们可以多加一个模板参数。
解决方法1:
template<class T>
//template<class T2>
T Add(const T&left, const T&right)
{return left + right;
}
int main()
{int a = 1, b = 2;double c = 1.1, d = 2.2;/*cout << Add(a, b) << endl;cout << Add(c,d) << endl;*/cout << Add((double)a, c) << endl;cout << Add(a, (int)c) << endl;return 0;
}
我们在模板实例化对象之前强制类型转化。
我们去掉const会报错:
我们把a强制类型转换为double进行传参,a本身并没有发生改变,改变的是临时变量,临时变量具有常性,不能用引用来接收。
显示实例化
template<class T>
//template<class T2>
T Add(const T&left, const T&right)
{return left + right;
}
int main()
{int a = 1, b = 2;double c = 1.1, d = 2.2;/*cout << Add(a, b) << endl;cout << Add(c,d) << endl;*//*cout << Add((double)a, c) << endl;cout << Add(a, (int)c) << endl;*/cout << Add<double>(a, c) << endl;cout << Add<int>(a, c) << endl;return 0;
}
两个不同参数的模板
template<class T1, class T2>
//template<class T2>
T1 Add(const T1&left, const T2&right)
{return left + right;
}
int main()
{int a = 1, b = 2;double c = 1.1, d = 2.2;/*cout << Add(a, b) << endl;cout << Add(c,d) << endl;*//*cout << Add((double)a, c) << endl;cout << Add(a, (int)c) << endl;*/cout << Add(a, c) << endl;cout << Add(a, c) << endl;return 0;
}
模板类参数类似于函数参数。
模板函数与函数:
int Add(int a, int b)
{return a + b;
}
template<class T>T Add(T a, T b)
{return a + b;
}
int main()
{int a = 1, b = 2;Add(1, 2);return 0;
}
同名的模板函数与函数可以同时存在。
两个函数都可以调用的前提下,我们首先调用已经显示实例化的普通函数,模板函数还需要实例化。
显示调用模板函数:
模板函数与同名函数可以同时存在的原因:
两个函数虽然同名,但是他们的函数名修饰规则不同。
类模板
template<class T>
class Stack
{
public:Stack(int capacity = 4){_a = (T*)malloc(sizeof(T)*capacity);if (_a == nullptr){perror("malloc fail");exit(-1);}_top = 0;_capacity = capacity;}void Push(const T& x){_a[_top++] = x;}~Stack(){free(_a);_a = nullptr;_top = _capacity = 0;}
private:T*_a;size_t _capacity;size_t _top;
};
int main()
{Stack<int> s1(10);s1.Push(2);Stack<double> s2(20);s2.Push(3.3);return 0;
}
注意这两个类并不是同一个类型。
因为他们所占空间大小不同,int占4个字节,double占8个字节。
[]重载:
#define N 10
template<class T>
class Array
{
public:T&operator[](size_t i){return _a[i];}
private:T _a[N];
};
int main()
{Array <int> a1;a1[1] = 10;cout << a1[1] << endl;return 0;
}
并且我们知道,访问数组时容易出现越界而没有报错的情况,我们可以在这个重载函数中实现绝对检查:
我们也可以加上内联,提升效率。
inline T&operator[](size_t i){/* assert(i < 10);*/return _a[i];}