6.1 new 和 delete 用法
6.1.1 概述
在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。在C语言中是利用库函数malloc和free来分配和撤销内存空间的。C++提供了较简便而功能较强的运算符new和delete来取代malloc和free函数。
#include <iostream>
#include <stdlib.h>
using namespace std;
class Test
{
public:
Test()
{
cout << "Test构造函数" << endl;
}
~Test()
{
cout << "Test析构函数" << endl;
}
};
int main()
{
//Test t1; //栈空间创建对象
//创建对象 1、申请空间 2、调用构造函数初始化 C++中不用malloc创建对象
Test *pt = (Test *)malloc(sizeof(Test) * 1); //在堆空间申请一个对象大小的内存(并没有调用构造函数)
if (NULL == pt)
{
cout << "malloc failure" << endl;
}
free(pt); //释放内存,不是释放对象
// -------------------------------------------------------------------------
Test *pt2 = new Test; //1、申请内存(堆) 2、调用构造函数 自动调用构造函数
delete pt2; //调用析构函数
return 0;
}
运行结果:
注意: new和delete是运算符,不是函数,因此执行效率高。
6.1.2 使用方法
虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算符。new运算符的例子:
-
new运算符动态分配堆内存
使用形式:指针变量 = new 类型(常量), 指针变量 = new 类型 [表达式]
作用:从堆分配一块“类型”大小的存储空间,返回首地址。
其中:“常量”是初始化值,可缺省;创建数组对象时,不能为对象指定初始值。 -
delete运算符释放已分配的内存空间
使用形式:delete 指针变量 ; delete[] 指针变量
其中:“指针变量”一定是new返回的指针 -
一些例子
(1)new int;
//开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针)(2)new int(100);
//开辟一个存放整数的空间,并指定该整数的初值为100,返回一个指向该存储空间的地址(3)new char[10];
//开辟一个存放字符数组(包括10个元素)的空间,返回首元素的地址(4)new int[5][4];
//开辟一个存放二维整型数组(大小为5*4)的空间,返回首元素的地址(5)float *p=new float (3.14159);
//开辟一个存放单精度数的空间,并指定该实数的初值为//3.14159,将返回的该空间的地址赋给指针变量p注意:用new分配数组空间时不能指定初值。如果由于内存不足等原因而无法正常分配空间,则new会返回一个空指针NULL,用户可以根据该指针的值判断分配空间是否成功。
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
cout << "无参构造函数" << endl;
}
Test(int a, int b)
{
cout << "有参构造函数" << endl;
}
~Test()
{
cout << "析构函数" << endl;
}
};
int main()
{
int *p1 = new int; //给一个整数申请空间
cout << *p1 << endl;
delete p1;
char *p2 = new char; //给一个字符申请空间
delete p2;
int *p3 = new int(100); //给一个整数申请空间同时初始化为100
cout << *p3 << endl;
delete p3;
char *p4 = new char[10]; //给十个字符申请空间
delete[] p4;
Test *t1 = new Test;
delete t1;
Test *t2 = new Test(1, 2);
delete t2;
return 0;
}
运行结果:
6.2 初始化对象列表
6.2.1 对象初始化列表出现原因
-
类对象作为成员变量并且该类没有提供无参构造函数
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,没有默认构造函数。这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,
如果没有初始化列表,那么他将无法完成第一步,就会报错。 -
成员变量被const修饰(初始化和赋值不同)
当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,
因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
6.2.2 C++中提供初始化列表对成员变量进行初始化
语法规则
Constructor::Contructor() : m1(v1), m2(v1,v2), m3(v3)
{
// some other assignment operation
}
6.2.3 注意初始化和赋值的概念
- 初始化:被初始化的对象正在创建
- 赋值:被赋值的对象已经存在
6.2.4 注意
- 成员变量的初始化顺序与声明的顺序相关,与在初始化列表中的顺序无关
- 初始化列表先于构造函数的函数体执行
#include <iostream>
using namespace std;
class Date
{
private:
int year;
int mouth;
int day;
public:
/*Date()
{
year = 1999;
mouth = 1;
day = 1;
}*/
Date(int y, int m, int d)
{
year = y;
mouth = m;
day = d;
}
};
//对象初始化列表:1、类对象作为成员变量并且该类没有提供无参构造函数 2、成员变量被const修饰(初始化和赋值不同)
class Student
{
private:
const int id;
Date birth;
public:
Student(int i, int y, int m, int d) : birth(y, m, d), id(i) //对象初始化列表
{
}
};
int main()
{
Student s1(1, 1999, 2, 2);
return 0;
}