在前面介绍的方法定义的对象都是静态的,在程序运行过程中,对象所占的空间是不能随时释放的。在c++中动态内存分配技术可以保证程序在运行过程中按照实际需要申请适量的内存,使用结束后还可以释放,这种在程序运行过程中申请和释放的存储单元也成为堆对象,申请和释放过程一般称为建立和删除。
在c++程序中建立和删除堆对象使用两个运算符:new和delete。
new:
要了解为哪种数据类型分配内存,new将找到一个长度正确的内存块,并返回该内存块的地址,程序员的责任是将该地址赋给一个指针:
如下:int *pn = new int; new int 告诉程序,需要适合存储int的内存。new运算符根据类型,来确定需要多少个字节的内存,然后,他找到这样的内存,并返回地址。接下来,将地址付给pn,pn是被声明为指向int的指针,现在pn是地址,而*pn是存储在那里的值,将这种方法与将变量的地址赋给指针进行比较。
#include<iostream>
using namespace std;
int main()
{
int *Pt;
Pt = new int;//只进行了定义,没有进行初始化
cout << *Pt << endl;//所以输出的是个垃圾值
Pt = new int();//带括号,括号中不写参数,表示将0对该对象初始化
cout << *Pt << endl;
Pt = new int(8);//动态分配了用于存放int的空间,并将初值8存入该空间里,然后将首地址赋给Pt
cout << *Pt << endl;
return 0;
}
如果用new来建立对象,如果该类存在用户定义的默认构造函数,则new T和new T(),这两种写法的效果是相同的,都会调用这个默认构造函数,如果用户没有定义默认构造和函数,使用new T创建的对象时,会调用系统生成的隐含的默认构造函数;使用
new T()创建对象时候,系统除了执行默认构造函数会执行的那些操作外,还会为基本数据类型和指针类型的成员用0赋初值,而且这一过程是递归的。
#include<iostream>
using namespace std;
class Time
{
private:
int hour;
int minute;
int second;
public:
void display();
};
void Time::display()
{
cout << hour << endl;
cout << minute << endl;
cout << second <<endl;
}
int main()
{
Time *Pt = new Time;//l垃圾值
Pt->display();
Time *Pt1 = new Time();
Pt1->display();//0,0,0
}
运算符delete用来删除由new建立的对象,释放指针所指向的内存空间,格式为:
delete 指针名
如果被删除的是对象,该对象的析构函数将被调用,对于用new建立的对象,只能使用delete进行一次删除操作,如果对同一内存空间多次使用delete进行删除将会导致运行错误。用new分配内存,必须用delete加以释放,否则会导致动态分配的内存无法回收,使得程序占据的内存越来越大,这叫做内存泄漏.
使用运算符new也可以创建数组类型的对象,它可以是任何能够得到正整数值的表达式、
用new动态创建一维数组,在方括号后仍然可以加小括号"()",但小括号内不能带任何参数,是否加“()”的区别在于:不加“()”,则对数组每个元素的初始化,与执行“new T”时所进行初始化的方式相同;加"()",则与执行“new T()”所进行初始化的方式相同,
如:int *p= new int [10]();则可以方便地为动态创建的数组用0值初始化,如果是用new建立的数组,用delete删除时在指针名前面要加"[]",格式如下:delete[] 指针名
#include<iostream>
using namespace std;
class Point
{
public:
Point() :x(0), y(0){ cout << "无参构造函数" << endl; }
Point(int _x, int _y) :x(_x), y(_y){ cout << "两个参数的构造函数:" << endl; }
~Point(){ cout << "析构函数:" << endl; }
int GetX()const;
int GetY()const;
void move(int newX,int newY);
void Show();
private:
int x;
int y;
};
int Point::GetX()const
{
return x;
}
int Point::GetY()const
{
return y;
}
void Point::move(int newX, int newY)
{
x = newX;
y = newY;
}
void Point::Show()
{
cout << "x:" << x << endl;
cout << "y:" << y << endl;
}
int main()
{
Point *Ptr1 = new Point[2];
Ptr1[0].Show();
Ptr1[1].move(12,34);
Ptr1[1].Show();
delete[]Ptr1;
return 0;
}
以上代码是自己用new申请了一个对象数组,通过自定义无参构造函数初始化所有的数据成员都为0,再定义了带有两个参数的构造函数,进行初始化,用new申请了含有两个对象的对象数组,分别赋值,最后使用delete进行释放内存,会自动调用析构函数。
接下来顶一个动态数组类:
#include<iostream>
#include<cassert>
using namespace std;
class Point
{
public:
Point() :x(0), y(0){ cout << "无参构造函数" << endl; }
Point(int _x, int _y) :x(_x), y(_y){ cout << "两个参数的构造函数:" << endl; }
~Point(){ cout << "析构函数:" << endl; }
int GetX()const;
int GetY()const;
void move(int newX,int newY);
void Show();
private:
int x;
int y;
};
class ArrayOfPoints
{
public:
ArrayOfPoints(int _size):size(_size)
{
cout << "我的初始化构造函数\n" << endl;
points = new Point[size];
}
~ArrayOfPoints()
{
cout << "进行析构:然后调用delete[]points 释放内存" << endl;
delete[]points;
}
Point &Array(int index);
private:
Point *points;
int size;
};
int Point::GetX()const
{
return x;
}
int Point::GetY()const
{
return y;
}
void Point::move(int newX, int newY)
{
x = newX;
y = newY;
}
void Point::Show()
{
cout << "x:" << x << endl;
cout << "y:" << y << endl;
}
Point& ArrayOfPoints::Array(int index)
{
assert(index >= 0 && index < size);
return points[index];
}
int main()
{
ArrayOfPoints temp(2);
temp.Array(0).move(23,24);
temp.Array(0).Show();
return 0;
}
分析这个程序,在此程序中,定义了一个动态数组类,将进行动态创建数组的内容放在了此类中,但是要操作进行对原来的类进行操作,因为动态数组不能直接通过“[]”去创建访问原本类Point的内容,定义了个函数 Point& temp(),进行返回原类的操作。