C語言動態內存管理
C語言使用malloc/calloc/realloc/free進行動態內存管理。
void Test ()
{
int* p1 = (int*) malloc (sizeof (int)*4);
free(p1 );
// 1.calloc/realloc/malloc 的區別是什麼?
int* p2 = (int*) calloc(4, sizeof (int));
int* p3 = (int*) realloc(p2 , sizeof( int)*6);
// 這裏需要free(p2)嗎?
free(p2 );
free(p3 );
}
C++動態內存管理
C++通過new和delete動態管理內存。
new/delete動態管理對象。
new[]/delete[]動態管理對象數組。
void Test ()
{
int* p4 = new int; // 動態分配4個字節(1個 int)的空間單個數據
int* p5 = new int(3); // 動態分配4個字節(1個 int)的空間並初始化爲3
int* p6 = new int[3]; // 動態分配12個字節(3個 int)的空間
delete p4 ;
delete p5 ;
delete[] p6 ;
}
注意malloc/free、new/delete、new[]/delete[]
一定匹配使用,一定匹配使用,一定匹配使用!!!重要的事說三遍!否則可能出現內存泄露甚至崩潰的問題
void Test ()
{
// 以下代碼沒有匹配使用,會發生什麼?有內存泄露嗎?會崩潰嗎?
int* p4 = new int;
int* p5 = new int(3);
int* p6 = new int[3];
int* p7 = (int*) malloc(sizeof (int));
delete[] p4 ;
delete p5 ;
free(p5 );
delete p6 ;
delete p7 ;
}
內存管理
int globalVar = 1;
static int staticGlobalVar = 1;
void Test ()
{
// 1.全局變量、全局靜態變量、局部靜態變量、局部變量之間的區別是什麼?
static int staticVar = 1;
int localVar = 1;
// 2.下面的a1和 a2和a3 有什麼區別和聯繫?
int a1 [10] = {1, 2, 3, 4};
char a2 [] = "abcd";
char* a3 = "abcd";
int * p1 = ( int*) malloc (sizeof ( int)*4);
int * p2 = ( int*) calloc (4, sizeof ( int));
int * p3 = ( int*) realloc (p2 , sizeof( int )*4);
free (p1 );
free (p3 );
int * p4 = new int;
int * p5 = new int(3);
int * p6 = new int[3];
delete p4 ;
delete p5 ;
delete [] p6 ;
}
棧又叫堆棧,非靜態局部變量/函數參數/返回值等等,棧是向下增長的。
內存映射段是高效的I/O映射方式,用於裝載一個共享的動態內存庫。用戶可使用系統接口創建共享共享內存,做進程間通信。(現在只需要瞭解一下)
堆用於程序運行時動態內存分配,堆是可以上增長的。
數據段--存儲全局數據和靜態數據。
代碼段--可執行的代碼/只讀常量。
【思考】
我們知道C++是兼容C的,那麼已經有C庫malloc/free等來動態管理內存,爲什麼C++還要定義new/delete運算符來動態管理內存?
深入理解C++動態內存管理
【malloc/free和new/delete的區別和聯繫?】
它們都是動態管理內存的入口。
malloc/free是C/C++標準庫的函數,new/delete是C++操作符。
malloc/free只是動態分配內存空間/釋放空間。而new/delete除了分配空間還會調用構造函數和析構函數進行初始化與清理(清理成員)。
malloc/free需要手動計算類型大小且返回值會void*,new/delete可自己計算類型的大小,返回對應類型的指針。
class Array
{
public :
Array (size_t size = 10)
: _size(size )
, _a(0)
{
cout<<"Array(size_t size)" <<endl;
if (_size > 0)
{
_a = new int[ size];
}
}
~ Array()
{
cout<<"~Array()" <<endl;
if (_a )
{
delete[] _a ;
_a = 0;
_size = 0;
}
}
private :
int*_a ;
size_t _size ;
};
void Test ()
{
Array* p1 = (Array*) malloc(sizeof (Array));
Array* p2 = new Array;
Array* p3 = new Array(20);
Array* p4 = new Array[10];
free(p1 );
delete p2 ;
delete p3 ;
delete[] p4 ;
}
C++的其他內存管理接口(placement版本)
void * operator new (size_t size);
void operator delete (size_t size);
void * operator new [](size_t size);
void operator delete[] (size_t size);
總結:
operator new/operator delete operator new[]/operator delete[] 和 malloc/free用法一樣。
他們只負責分配空間/釋放空間,不會調用對象構造函數/析構函數來初始化/清理對象。
實際operator new和operator delete只是malloc和free的一層封裝。
new做了兩件事
調用operator new分配空間。
調用構造函數初始化對象。
delete也做了兩件事
調用析構函數清理對象
調用operator delete釋放空間
new[N]
調用operator new分配空間。
調用N次構造函數分別初始化每個對象。
delete[]
調用N次析構函數清理對象。(思考這裏怎麼N是怎麼來的?)
調用operator delete釋放空間。
定位new表達式(replacement版本)
定位new表達式是在已分配的原始內存空間中調用構造函數初始化一個對象。
new (place_address) type
new (place_address) type(initializer-list)
place_address必須是一個指針,initializer-list是類型的初始化列表。
class Array
{
public :
Array (size_t size = 10)
: _size(size )
, _a(0)
{
cout<<"Array(size_t size)" <<endl;
if (_size > 0)
{
_a = new int[ size];
}
}
~ Array()
{
cout<<"~Array()" <<endl;
if (_a )
{
delete[] _a ;
_a = 0;
_size = 0;
}
}
private :
int* _a ;
size_t _size ;
};
void Test ()
{
// 1.malloc/free + 定位操作符new()/顯示調用析構函數,模擬 new和delete 的行爲
Array* p1 = (Array*) malloc(sizeof (Array));
new(p1 ) Array(100);
p1->~Array ();
free(p1 );
// 1.malloc/free + 多次調用定位操作符new()/顯示調用析構函數,模擬 new[]和delete[] 的行爲
Array* p2 = (Array*) malloc(sizeof (Array)*10);
for(int i = 0; i < 10; ++i )
{
new(p2 +i) Array;
}
for(int i = 0; i < 10; ++i )
{
p2[i ].~Array();
}
free(p2 );
}
深度剖析new/delete & new[]/delete[]
class Array
{
public :
Array (size_t size = 10)
: _size(size )
, _a(0)
{
cout<<"Array(size_t size)" <<endl;
if (_size > 0)
{
_a = new int[ size];
}
}
~ Array()
{
cout<<"~Array()" <<endl;
if (_a )
{
delete[] _a ;
_a = 0;
_size = 0;
}
}
private :
int* _a ;
size_t _size ;
};
void Test ()
{
//
// 1.通過【調試】new/delete、 new[]/delete[]剖析系統在裏面到底做了些什麼?
// 2.分析delete[] 的對象是自定義類型時,是怎麼知道要調用 N次析構函數的?
//
int* p1 = new int;
delete p1 ;
Array* p2 = new Array;
delete p2 ;
int* p3 = new int[10];
delete p3 ;
Array* p4 = new Array[10];
delete[] p4 ;
}