1. 使用new动态分配内存:若没有足够内存,则new返回0(空值指针null pointer);
2. 不要使用delete释放不是new分配的内存,delete释放指针指向的内存,但不会删除指针本身;
3、对空值指针应用delete是安全的;
4、创建数组时的静态联编与动态联编:数组声名int a[10], 静态联编,数组的长度在编译时确定;用new[]创建数组,动态联编,运行时为数组分配内存空间。动态-运行时分配内存。
C++有3种管理数据内存的方式:自动存储、静态存储、动态存储(自由存储空间或堆)(三块独立的内存)
自动存储:(auto / register ) 自动变量的持久性为自动的,在程序开始执行其所属的函数或代码块时创建,执行完后释放。
auto: in stack LIFO
register: in CPU register,使用寄存器处理变量,提高访问速度;没有内存地址,不能用&取地址。
静态存储:(global / static ) 在程序整个运行期间都存在. (外部链接性、内部链接性、无链接性)
初始化为0。
int global = 1000; //外部链接性,可在程序的其他文件使用, 使用时要用extern声名 (外部变量/全局变量)
static int one_file = 50; //内部链接性,只能在本文件使用 (函数如果为static也一样,只能在该文件中被调)
int main(){ ... }
void func(){
static int count = 0; //静态局部变量,只在该代码中可用,但它在该代码不活动时始终存在。
}
可用extern重新声名以前定义过的外部变量;
访问被隐藏的外部变量(被局部变量隐藏了):用作用域解析符(::)::n 表示使用n的全局版本
const char * const months[12] = {"Jan", "Feb", "Mar",...};
//第一个const防止字符串被修改,第二个const确保数组中每个指针始终指向它最初指向的字符串。
mutable限定符:const/volatile/mutable const禁止修改结构成员,但是mutable使const结构中的成员不受这种限制
struct data { char name[30]; mutable int accesses; };
const data a = {....}; strcpy(a.name, "fdsf"); //not allowed a.access++//allowed
外部定义的const数据的链接性为内部的,跟static一样
动态存储:(free store / heap) new/delete, malloc/free
1、使用new来设置指针的语句必须位于函数中,因为只能使用常量表达式来初始化静态存储变量:
float * p;
//float *p = new float[20]; //initialization with non-const not allowed here
main (){ p = new float[20]; }
2、布局new操作符 (placement new): 自己指定空间为placement new提供内存空间,而不是在heap中分配
#include<new>
char buffer[512];
......double *pd1, *pd2;
pd1 = new double[N];
pd2 = new (buffer) double[N];
注:不能用delete [] pd2; 来释放分配的内存,buffer指向的内存是静态的,delete只能用于指向常规new分配的堆内存(free store)
内存泄漏(memory leak)- 被分配的内存再也不能使用了,也无法回收
(new和delete使用不恰当,没有配对使用而产生)
如果使用new操作符在自由存储空间上创建变量后,没有调用delete,则即使包含指针的内存由于作用域和对象生命周期的原因而被释放,在自由存储区动态分配的变量或结构也将继续存在,
这样,将无法访问free store空间中的结构,因为指向这些内存的指针无效,因此这些被分配的内存将无法使用,从而导致内存泄漏。
一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内存。应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了检测内存泄漏的关键是要能截获住对分配内存和释放内存的函数的调用。截获住这两个函数,我们就能跟踪每一块内存的生命周期,比如,每当成功的分配一块内存后,就把它的指针加入一个全局的list中;每当释放一块内存,再把它的指针从list中删除。这样,当程序结束的时候,list中剩余的指针就是指向那些没有被释放的内存。这里只是简单的描述了检测内存泄漏的基本原理,详细的算法可以参见Steve Maguire的<<Writing Solid Code>>。
如果要检测堆内存的泄漏,那么需要截获住malloc/realloc/free和new/delete就可以了(其实new/delete最终也是用malloc/free的,所以只要截获前面一组即可)。对于其他的泄漏,可以采用类似的方法,截获住相应的分配和释放函数。比如,要检测 BSTR的泄漏,就需要截获SysAllocString/SysFreeString;要检测HMENU的泄漏,就需要截获CreateMenu/ DestroyMenu。(有的资源的分配函数有多个,释放函数只有一个,比如,SysAllocStringLen也可以用来分配BSTR,这时就需要截获多个分配函数)