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

C++ 动态内存管理

2016-06-21 13:33 295 查看
我们都知道在c++中可以用new/malloc动态分配内存空间,delete/free释放动态开辟的内存空间。

  1. 那么既然c++中有了可以动态开辟内存的函数为什么又要有new/delete呢?

C++中的malloc/free是继承C语言中的malloc/free,它的用法和在C语言中的用法一模一样。malloc只是单纯的开辟内存空间而不进行初始化,free只是将动态开辟的内存空间给释放了。

对于内置类型来说,malloc/free开辟和释放内存没有任何问题;对于非内置类型而言,由于对象创建过程中调用构造函数进行初始化,在对象的消除时要调用析构函数进行一些清理工作,显然,malloc/free无法完成这些事情。

因此,C++提供了new/delete两个操作符,用new在动态分配内存的时候调用构造函数进行初始化,delete在释放内存的时候自动调用析构函数进行清理。

  2.new/delete的使用
A为非内置类型
class A
{
public:
A(int a = 0, int b = 0)
:_a(_a)
,_b(b)
{
cout << "A() "<<endl;
}
~A()
{
cout << "~A() " << endl;
}
private:
int _a;
int _b;
};
测试/解析如下:

               


注意:new/delete , new[]/delete[] 要匹配 使用!!!

3.new和delete的内部实现:

通过跟踪调试程序,我们就可以发现new/delete内部是通过调用一些函数来实现的。

new的内部实现是通过调用一下函数实现的:
char* operator new(size_t count);
char* operator new[](size_t count);

调用顺序:



delete内部是通过调用以下两个函数实现的:

void operator delete(char *p);

void operator delete(char *p);

 

调用顺序如下:



4.new/delete,new[]/delete[]为什么要成对出现?

1.malloc/free为防止内存泄漏,一定要成对出现。

2.new和delete成对出现的原因则是:new开辟内存空间是调用构造函数创建对象,而如果不用delete释放空间而是
用free,那么释放空间之前不会执行析构函数,有可能会导致内存泄漏。
A *pa=new A;

free(pa);//错误

delete pa;//正确

3.new[]和delete[]为什么要成对出现呢? 

对于new:

举例: (在VS2013版本 下)

内置类型
void funTest2()
{
int *pa = new int[10];
delete pa;    //程序不会崩溃

}
int main()
{
funTest2();
return 0;
}


非内置类型
A为上面的自定义类
void funTest1()
{
A*pb = new A[10];
delete pb;  //程序崩溃
}
int main()
{
funTest1();
return 0;
}


对上述现象分析:

追踪   int *pa = new int[10];   发现调用operator new[](size_t count)函数



追踪    A*pb = new A[10];  发现 调用  operator new[](size_t count) 函数



对上述现象总结:

说明了new在开辟内置类型的空间时,开辟得空间数量是指定的空间数量,字节数是指定的数量乘以类型的大小。

而在开辟非内置类型空间时,除了开辟指定数量的空间以外,还多开辟4个字节的空间。

为什么这这里是84呢?(前面可以知道sizeof(A)为8)

new开辟非内置类型的空间时传给operator new[](size_t count)的count是类型的大小*空间的数量在加上4个字节,最前面的空间里放的是要执行析构函数的次数。它返回给a2的地址是最前面的空间的后一个空间的地址。

 所以很容易理解内置类型new/delete,new[]/delete[] 交错使用可以:内置类型没有析构函数,所以不需要开辟
通过调试,看看内存中有什么:



对于delete:

非内置类型用delete[]在释放空间时调用operator delete[](char *p),而此时的p被编译器内部处理过后,它指向的是这些连续空间的最前面一个空间的地址,因此,而传给operator delete(char *p)的地址是处理过后的地址,因此,他可以释放一块连续的空间并且直到调用析构函数的次数。

而如果用delete,则直接调用operator delete(char *p),传给p的地址是a2的地址,如果释放它,就相当于释放动态开辟空间的一部分,这样会造成内存泄露,使程序崩溃,而编译器不知道调用多少次析构函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: