目录
1.malloc与new
我们使用一个malloc函数,进入到反汇编查看代码
1.malloc函数
2.new关键字
3.free函数
4.delete关键字
5.new和delete关键字用法
我们发现malloc和new调用的函数到最后都是同一个系统函数,new调用了库函数malloc,编译器替我们实现了某一下功能。
假如,我们想在堆中分配1024个字节的空间,那么我们可以通过malloc实现
那如果我们想在堆中分配一个int、char、struct类型的空间呢
这里就可以用到new了,new关键字让编译器替我们实现这一功能。
#include<stdio.h>
int main()
{
int* pi=new int;//分配1个四字节的空间
delete pi;
int* pi=new int(5);//分配1个四字节空间并赋值为5
delete pi;
int* pi=new int[5];//分配4个四字节空间
delete[5] pi;
Base* pi=new Base;//分配1个类字节的空间
delete pi;
Base* pi=new Base[3];//分配3个类字节的空间
delete[3] pi;
Base* pi=new Base(1,2);//分配1个类的空间,构造函数传参1,2
delete pi;
return 0;
}
通过析构函数来判断是否释放空间
#include<stdio.h>
#include<stdlib.h>
class Base
{
int x;
int y;
public:
Base(int x,int y)
{
this->x=x;
this->y=y;
}
~Base()
{
printf("delete Base\n");//析构函数
}
void Print()
{
printf("%d %d\n",x,y);
}
};
int main()
{
Base* pi=new Base(1,2);
pi->Print();
delete pi;
return 0;
}
析构函数何时被调用
析构函数是在对象消亡时,自动被调用,用来释放对象占用的空间。
有四种方式会调用析构函数:
-
1.生命周期:对象生命周期结束,会调用析构函数。
-
2.delete:调用delete,会删除指针类对象。
-
3.包含关系:对象Dog是对象Person的成员,Person的析构函数被调用时,对象Dog的析构函数也被调用。
-
4.继承关系:当Person是Student的父类,调用Student的析构函数,会调用Person的析构函数。
2.Vector
什么是Vector?
个人认为vector其实更像一个“遥控器”,它具有很多功能,我们根据自己的需求去“按按钮”
- vector是表示可变大小数组的序列容器。
- 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
- 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
- vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
- 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
- 与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists和forward_lists统一的迭代器和引用更好。
3.作业
写一个Vector,实现增删查改等功能
#include<stdio.h>
#include<Windows.h>
#define m_SUCCESS 1 // 成功
#define m_ERROR -1 // 失败
#define m_MALLOC_ERROR -2 // 申请内存失败
#define m_INDEX_ERROR -3 // 错误的索引号
template <class T_ELE>
class Vector
{
public:
Vector();
Vector(DWORD dwSize);
~Vector();
public:
DWORD at(DWORD dwIndex,OUT T_ELE* pEle); //根据给定的索引得到元素
DWORD push_back(T_ELE Element); //将元素存储到容器最后一个位置
VOID pop_back(); //删除最后一个元素
DWORD insert(DWORD dwIndex, T_ELE Element); //向指定位置新增一个元素
DWORD capacity(); //返回在不增容的情况下,还能存储多少元素
VOID clear(); //清空所有元素
BOOL empty(); //判断Vector是否为空 返回true时为空
DWORD erase(DWORD dwIndex); //删除指定元素
DWORD size(); //返回Vector元素数量的大小
private:
BOOL expand();
private:
DWORD m_dwIndex; //下一个可用索引
DWORD m_dwIncrement; //每次增容的大小
DWORD m_dwLen; //当前容器的长度
DWORD m_dwInitSize; //默认初始化大小
T_ELE *m_pVector; //容器指针
};
template <class T_ELE>
Vector<T_ELE>::Vector() //无参数的构造函数
:m_dwInitSize(4),m_dwIncrement(5)
{
//1.创建长度为m_dwInitSize个T_ELE对象
m_pVector=new T_ELE[m_dwInitSize];
//2.将新创建的空间初始化
memset(m_pVector,0,sizeof(T_ELE)*m_dwInitSize);
//3.设置其他值
m_dwIndex=0;
m_dwLen=m_dwInitSize;
}
template <class T_ELE> //有参数的构造函数
Vector<T_ELE>::Vector(DWORD dwSize)
:m_dwIncrement(5)
{
//1.创建长度为dwSize个T_ELE对象
m_pVector=new T_ELE[dwSize];
//2.将新创建的空间初始化
memset(m_pVector,0,sizeof(T_ELE)*dwSize);
//3.设置其他值
m_dwIndex=0;
m_dwLen=dwSize;
}
template <class T_ELE> //释放空间
Vector<T_ELE>::~Vector()
{
//释放空间 delete[]
delete [] m_pVector;
m_pVector=NULL;
}
template <class T_ELE>
BOOL Vector<T_ELE>::expand() //进行扩容
{
// 1. 计算增加后的长度
DWORD tmp_Size=m_dwLen+m_dwIncrement;
// 2. 申请空间
T_ELE* tmp_pVector = new T_ELE[tmp_Size];
memset(tmp_pVector,0,tmp_Size*sizeof(T_ELE));//初始化空间
// 3. 将数据复制到新的空间
memcpy(tmp_pVector,m_pVector,m_dwLen*sizeof(T_ELE));
// 4. 释放原来空间
delete[] m_pVector;
m_pVector=tmp_pVector;
tmp_pVector=NULL;
// 5. 为各种属性赋值
m_dwLen=tmp_Size; //此时不修改Index是因为在其他插入函数中有了对于长度属性的修改
return m_SUCCESS;
}
template <class T_ELE>
DWORD Vector<T_ELE>::push_back(T_ELE Element) //写入函数,如果空间里一个没存,就存在第一个 如果存了,就接着存
{
//1.判断是否需要增容,如果需要就调用增容的函数
if(m_dwIndex>=m_dwLen)
{
expand();
}
//2.将新的元素复制到容器的最后一个位置
memcpy(&m_pVector[m_dwIndex],&Element,sizeof(T_ELE));
//3.修改属性值
m_dwIndex++; //此时不修改长度属性是因为,再增容函数中已经有了对于长度属性的修改
return m_SUCCESS;
}
template <class T_ELE>
DWORD Vector<T_ELE>::insert(DWORD dwIndex, T_ELE Element) //插入函数
{
//1.判断索引是否在合理区间
if(dwIndex>m_dwLen || dwIndex<0)
{
return m_INDEX_ERROR;
}
//2.判断是否需要增容,如果需要就调用增容的函数
if(m_dwIndex>=m_dwLen)
{
expand();
}
// 0 1 2 3 4 5 6 7
//3.将dwIndex之后的元素后移
for(int i=m_dwIndex;i>dwIndex;i--)
{
memcpy(&m_pVector[i],&m_pVector[i-1],sizeof(T_ELE));
}
//4.将Element元素复制到dwIndex位置
memcpy(&m_pVector[dwIndex],&Element,sizeof(T_ELE));
//5.修改属性值
m_dwIndex++;
return m_SUCCESS;
}
template <class T_ELE>
DWORD Vector<T_ELE>::at(DWORD dwIndex,T_ELE* pEle)
{
//判断索引是否在合理区间
if(dwIndex>=m_dwIndex)
{
return m_INDEX_ERROR;
}
//将dwIndex的值复制到pEle指定的内存
memcpy(pEle,&m_pVector[dwIndex],sizeof(T_ELE));
return m_SUCCESS;
}
template <class T_ELE>
VOID Vector<T_ELE>::pop_back() //实现删除最后一个元素
{
//m_dwIndex前一个索引就是最后一个元素的索引
T_ELE x=0;
memcpy(&m_pVector[m_dwIndex-1],&x,sizeof(x));
//修改属性
m_dwIndex-=1;
}
template <class T_ELE>
DWORD Vector<T_ELE>::capacity() //在不增容的情况下,返回还能存储多少元素
{
DWORD x=m_dwLen-m_dwIndex;
return x;
}
template <class T_ELE>
VOID Vector<T_ELE>::clear() //清空所有元素
{
//初始化所有元素
memset(&m_pVector[0],0,sizeof(T_ELE)*m_dwLen);
//修改属性
m_dwIndex=0;
}
template <class T_ELE>
DWORD Vector<T_ELE>::size() //返回已有元素数量
{
//返回已有元素数量
return m_dwIndex;
}
template <class T_ELE> //判断Vector是否为空
BOOL Vector<T_ELE>::empty()
{
if(m_dwIndex==0)
return true;
else
return false;
}
template <class T_ELE>
DWORD Vector<T_ELE>::erase(DWORD dwIndex)
{
//判断接收索引是否非法
if(dwIndex>=m_dwIndex || dwIndex<0)
return m_INDEX_ERROR;
//判断元素个数是否为0
if(m_dwIndex!=0)
{
//删除指定索引元素
for(int i=dwIndex;i<m_dwIndex;i++)
{
memcpy(&m_pVector[i],&m_pVector[i+1],sizeof(T_ELE));
}
//将最后一个元素初始化
memset(&m_pVector[m_dwIndex-1],0,sizeof(T_ELE));
}
//修改属性
m_dwIndex-=1;
}
//其他函数。。自己实现
void Test()
{
Vector<int>* pVector=new Vector<int>(4);
pVector->push_back(1);
pVector->push_back(2);
pVector->push_back(3);
pVector->push_back(4);
//pVector->insert(0,9);
/*
int x=0;
pVector->at(3,&x);
printf("%d\n",x);
pVector->pop_back();
pVector->at(3,&x);
printf("%d\n",x);
*/
//printf("%d\n",pVector->capacity());
//pVector->clear();
//printf("%d\n",pVector->size());
//printf("%d\n",pVector->empty());
pVector->erase(0);
}
int main()
{
Test();
return 0;
}