您的位置:首页 > 编程语言 > C语言/C++

《c++高级编程》笔记--内存管理

2007-12-31 13:25 253 查看
作者:fbysss
msn:jameslastchina@hotmail.com
blog:blog.csdn.net/fbysss
声明:本文由fbysss原创,转载请注明出处
关键字:C++内存管理
《c++高级编程》笔记
1.new关键字
使用关键字new时,内存是在堆(heap)里分配的,不使用new,内存是在堆栈(stack)分配的。
句柄handle一般用来描述一个指针的指针。
之所以使用“句柄”,是因为句柄允许底层软件在必要时移动内存。
使用new的时候,会返回一个指针,并且必须要把这个指针存储到一个变量中。否则就成了孤立内存,因为没法释放了。

比如new int;这句话可以编译通过,但是无法管理。
new 与malloc的区别:
new 不仅仅可以分配内存空间,而且会构造对象,也就是说,在调用new时,会调用对象的构造函数。同理,delete会调用协构函数,而free不会。
建议只使用new和delete
2.数组
int len = 3;
//int * dynaArray = new int[len];//可以通过
int arr[len] ;//编译不通过,len必须是常量
dynaArray 只能说是半动态数组,运行期间要动态自由的改变数组长度,只能用vector了。
使用new给数组分配内存时,只能使用指针变量。int dynaArray[]=new int[len]是不可以的。
realloc()是c遗留函数,作用是按照新容量分配一个内存块,把旧数据移动到新位置,从而有效地改变数组长度。但建议在c++中不要使用。
new 一个对象数组的时候,比如Simple * mySimpleArray= new Simple[4]
Simple的构造函数会执行四次(很显然。不过就是创建多个对象)。
删除数组用delete[],但只有数组中的元素是纯对象时才会调用协构函数,也就是数,只是对于一维数组来讲的。多维数

组或者指针数组,就需要分别处理,分配内存也同样如此。
Simple ** mySimplePtrArray= new Simple*[4];
//单独分配:
for (int i = 0 ; i <4 ; i++){
mySimplePtrArray[i] = new Simple();
}
//单独释放:
for (int i = 0 ; i <4 ; i++){
delete mySimplePtrArray[i];
}
//最后释放数组本身:
delete[] mySimplePtrArray;

new 与delete配对使用
new []与delete[]配对使用。
3.多维数组
多维数组在内存中实际上是按照如一维数组那样顺序存放的。
要注意一点:多维数组不能像上面的一维数组那样初始化时长度为变量。
char ** board = new char[i][j]是编译不通过的。char[1][j] char[i][1]同样不行。
因为new分配是基于堆的,为其分配的内存是不连续的。正确的做法是,必须先为基于对的数组的第一维分配一个连续的

数组。该数组的每个元素实际上是指向另一个数组的指针,后面这个数组存储了对应第二维下标的元素。
char** allocateCharacterBoard(int xDimension,int yDimension)
{
char **myArray = new char * [xDimension];//分配第一维数组
for (int i = 0 ; i < xDimension; i ++)
{
myArray[i] = new char [yDimension];//分配子数组
}
}

释放内存:
void releaseCharacterBoard(char** myArray,int xDimension)//由于编译器无法识别数组长度,所以需要单独传入
{
for (int i = 0 ; i< xDimension; i ++){
delete[] myArray[i]; //释放子数组
}
delete[] myArray; //释放第一维数组。
}
问题:参考上面的程序,为何这里可以用new char[yDimension]分配,delete[]删除子数组,上面的程序却不可以呢?
实际上,仔细看看就知道了,还是一样的。只不过上面是一个一维数组,每个元素为指针罢了。

--数组是指针,但指针不一定是数组
比如指针参数可以用数组传入,而int * a = new int; a[1]就不知道是什么了,虽然能编译通过。
4.字符串
c语言中的字符串,长度是实际字符串长度(strlen函数)+1,因为有一个'/0'.
char msg [2]="/0";
strcat(msg,"123456789");
可以。但是char msg[1]="/0";错误,因为数组长度太小。

char *msg = new char[1];
strcpy(msg,"123456789");
可以通过,但是存在严重隐患,因为msg的预留空间太小,虽然msg可以正常显示了,但紧跟其后面的内容有就被覆盖掉了,一定要小心,strcpy,strcat都存在类似问题

推荐使用string来管理字符串。string.c_str()函数可以转换为c风格的字符串。
--------
char * prt= "hello";相当于const char* ptr = "hello";也就是说使用
ptr[1]='a';运行时会报错,因为字符串常量在内存中只有一个实例,该内存只读。
char stackArray[]="hello"; stackArray[1]='a'就可以了。
因为基于栈的变量在任何情况下都不可能引用其他地方的内存。
4.指针运算
myArray[2] 等价于 *(myArray+2)
5.函数指针
好处是可以把函数作为一个参数,这样,函数的具体实现可以根据需要进行替换。
6.内存泄露相关
--valgrind是linux下查找内存泄露的一个工具
--二次删除与无效指针
二次删除:
delete(ptr);
doSomething();//假设这里占用了刚才释放的内存空间
delete(ptr);//二次删除,把doSomething所占空间释放了,隐患。
无效指针:
delete(ptr);
ptr还可以用。但内容已经不知道是什么了。
--访问越界指针
比如一个字符串指针,按照设计,在'/0'之前操作是安全的,一旦超出这个范围,可能覆盖掉别的内容,从而导致程序崩溃。一个错误的例子:
void fillWithM(char * inStr)
{
int i = 0 ;
while(inStr[i]!='/0'){
inStr[i] = 'm';
i++;
}
}
本意是填充字符串为m,殊不知很可能这个字符串丢掉了'/0',结果,后面的内容就不能保证是否被覆盖了。
--智能指针auto_ptr可以把动态分配的对象在超出作用域时释放。语法很难看,等需要再研究。

另外要注意局部指针问题,因为指针是在函数内部分配的,调用该函数之后,很容易忘记去delete该指针,所以最好是先分配,再传入参数,再释放。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: