const修饰符
在C语言中,习惯使用#define来定义常量,例如#define PI 3.14,C++提供了一种更灵活、更安全的方式来定义常量,即使用const修饰符来定义常量。例如const float PI = 3.14;
const可以与指针一起使用,它们的组合情况复杂,可归纳为3种:指向常量的指针、常指针和指向常量的常指针
指向常量的指针:一个指向常量的指针变量
const char* pc = "abcd";
字符串常量该方法不允许改变指针所指的变量,即
pc[3] = ‘x'; 是错误的,
但是,由于pc是一个指向常量的普通指针变量,不是常指针,因此可以改变pc所指的地址,例如
pc = "ervfs";
该语句付给了指针另一个字符串的地址,改变了pc的值。
常指针:将指针变量所指的地址声明为常量
char* const pc = "abcd";
创建一个常指针,一个不能移动的固定指针,可更改内容,如
pc[3] = 'x';
但不能改变地址,如
pc = 'dsff'; 不合法
指向常量的常指针:这个指针所指的地址不能改变,它所指向的地址中的内容也不能改变
const char* const pc = "abcd";
内容和地址均不能改变
说明:
1.如果用const定义整型常量,关键字可以省略。即 const in bufsize = 100 与 const bufsize = 100等价;
2.常量一旦被建立,在程序的任何地方都不能再更改。
3.与#define不同,const定义的常量可以有自己的数据类型。
4.函数参数也可以用const说明,用于保证实参在该函数内不被改动
void型指针
void通常表示无值,但将void作为指针的类型时,它却表示不确定的类型。这种void型指针是一种通用型指针,也就是说任何类型的指针值都可以赋给void类型的指针变量。
需要指出的是,这里说void型指针是通用指针,是指它可以接受任何类型的指针的赋值,但对已获值的void型指针,对它进行再处理,如输出或者传递指针值时,则必须再进行显式类型转换,否则会出错。
void* pc;
int i = 123;
char c = 'a';
pc = &i;
cout << pc << endl; //输出指针地址
cout << *(int*)pc << endl; //输出值123
pc = &c;
cout << *(char*)pc << endl; //输出值a
关于new和delete
下面对new和delete的使用再做一下几点说明:
用运算符new分配的空间,使用结束后应该用也只能用delete显式地释放,否则这部分空间将不能回收而变成死空间。
在使用运算符new动态分配内存时,如果没有足够的内存满足分配要求,new将返回空指针(NULL)。
使用运算符new可以为数组动态分配内存空间,这时需要在类型后面加上数组大小。
1 指针变量名 = new 类型名[下标表达式];
2 int *p = new int[10];
释放动态分配的数组存储区时,可使用delete运算符。
1 delete []指针变量名;
2 delete p;
new 可在为简单变量分配空间的同时,进行初始化
指针变量名 = new 类型名(初值);
int *p;
p = new int(99);
···
delete p;
定位new
不会申请空间
一般的new运算符负责在heap堆中找到一个足以能够满足要求的内存块。
new运算符还有另一种变体:定位new运算符(placement new),它能够让程序员指定要使用的位置。既将new运算符用于提供了的地址。
定位new运算符在头文件中。
定位new运算符直接使用传递给它的地址,它不负责判断哪些内存单元已被使用,也不查找未使用的内存块。这将一些内存管理的负担交给了程序员。
int main()
{
Object *obj=nullptr;
obj = (object*)::operator new(sizeof(Object));
//简单来说就是new运算符只是返回传递给它的地址,并将其强制转换为void *,以便能够赋给任何指针类型。
new(boj) Object(12);
obj->~Object();
::operator delete(obj);
}
用将定位new运算符来创建新的类对象后,当该对象消亡是时,程序并不会自动地调用其析构函数,所以必须显示地调用析构函数。这个少数的需要显示调用析构函数的情况之一。
需要注意的是,对于使用定位new运算符创建的对象,应以与创建顺序相反的顺序进行删除。原因在于,晚创建的对象可能依赖于早创建的对象。另外,仅当所有对象都被销毁后,才能释放用于储存这些对象的缓冲区。