內(nèi)存管理的基礎(chǔ)是要知道怎么獲得以及釋放內(nèi)存,如你所知,在C/C++中就是調(diào)用new和delete操作。
1. 分清operator new和new operator
全局函數(shù)operator new通常這樣聲明:
void * operator new(size_t size);
返回值類型是void*,表示其返回的是一個(gè)未經(jīng)處理(raw)的指針,指向未初始化的內(nèi)存。參數(shù)size_t確定分配多少內(nèi)存。你能增加額外的參數(shù)重載函數(shù)operator new,但是第一個(gè)參數(shù)類型必須是size_t。頭文件中有一個(gè)很好的重載的例子,那就是placement new,它看上去象這樣:
void * operator new(size_t, void *location)
{
return location;
}
這初看上去有些陌生,但它卻是new操作符的一種常見(jiàn)重載方法,使用一個(gè)額外的變量buffer,當(dāng)new操作符隱含調(diào)用operator new函數(shù)時(shí),把這個(gè)變量傳遞給它。被調(diào)用的operator new函數(shù)除了持有強(qiáng)制的參數(shù)size_t外,還必須接受void*指針參數(shù),指向構(gòu)造對(duì)象占用的內(nèi)存空間。未被使用的(但是強(qiáng)制的)參數(shù)size_t沒(méi)有參數(shù)名字,以防止編譯器警告說(shuō)它未被使用。在使用placement new的情況下,調(diào)用者已經(jīng)獲得了指向內(nèi)存的指針,因?yàn)檎{(diào)用者知道對(duì)象應(yīng)該放在哪里。placement new需要做的就是返回傳遞給它的指針。
我們更經(jīng)常使用的new是new操作符(new operator),而非操作符new(operator new),如當(dāng)你使用new操作符構(gòu)建一個(gè)對(duì)象的時(shí)候,實(shí)際上做了兩件事情,一是調(diào)用operator new函數(shù)獲取內(nèi)存,二是調(diào)用對(duì)象的構(gòu)造函數(shù),如:
string *ps = new string("Hello, world!");
它完成與下面代碼相似的功能:
void *memory = operator new(sizeof(string)); // 為String對(duì)象得到未經(jīng)處理的內(nèi)存
call string::string("Hello, world!") on *memory; // 調(diào)用構(gòu)造函數(shù)初始化內(nèi)存中的對(duì)象
string *ps = static_cast(memory); // ps指針指向新的對(duì)象
注意第二步中構(gòu)造函數(shù)的調(diào)用只能由編譯器完成,用戶是不允許這樣操作的,也就是說(shuō)如果你想建立一個(gè)堆對(duì)象就必須用new操作符,不能直接像上面一樣調(diào)用構(gòu)造函數(shù)來(lái)初始化堆對(duì)象。
new操作符(new operator)是編譯器內(nèi)置的,其行為被語(yǔ)言固定下來(lái),不受用戶控制。但是它們所調(diào)用的內(nèi)存分配函數(shù)也就是操作符new(operator new)則可以根據(jù)需要進(jìn)行重載。試著回顧new操作符(new operator)與操作符new(operator new)的關(guān)系,如果你想在堆上建立一個(gè)對(duì)象,應(yīng)該用new操作符。它既分配內(nèi)存又為對(duì)象調(diào)用構(gòu)造函數(shù)。如果你僅僅想分配內(nèi)存,就應(yīng)該調(diào)用operator new函數(shù),它不會(huì)調(diào)用構(gòu)造函數(shù)。如果你想定制自己獨(dú)有的內(nèi)存分配過(guò)程,你應(yīng)該重載全局的operator new函數(shù),然后使用new操作符,new操作符會(huì)調(diào)用你定制的operator new。如果你想在一塊已經(jīng)獲得指針的內(nèi)存里建立一個(gè)對(duì)象,應(yīng)該使用placement new。
最后需要記住的一點(diǎn)是,delete和new一樣具有以上的特性,只是需要注意的一點(diǎn)是delte操作符中是首先調(diào)用對(duì)象的析構(gòu)函數(shù),然后再調(diào)用operator delete函數(shù)的。
2. 針對(duì)數(shù)組的new[]和delete[]操作
建立數(shù)組時(shí)new操作符(new[])的行為與單個(gè)對(duì)象建立(new)有少許不同:
第一是內(nèi)存不再調(diào)用用operator new函數(shù)進(jìn)行分配,代替以operator new[]函數(shù)(常稱作array new)。它與operator new一樣能被重載,允許定制數(shù)組的內(nèi)存分配,就象定制單個(gè)對(duì)象內(nèi)存分配一樣。
第二個(gè)不同是new[]操作時(shí)調(diào)用構(gòu)造函數(shù)的數(shù)量。對(duì)于new[]而言,在數(shù)組里的每一個(gè)對(duì)象的構(gòu)造函數(shù)都必須被調(diào)用。
delete[]操作符的語(yǔ)義基本上和new[]相同,他們的實(shí)現(xiàn)類似這樣:
void * operator new[](size_t size)
{
cout << "new size of array in new[](): " << size << endl;
int *g =(int *) malloc(sizeof(size));
return g;
}
void operator delete[](void* p)
{
cout << "delete address of array pointer in delete[](): " << p << endl;
free(p);
}
3. operator new和delete函數(shù)的實(shí)現(xiàn)
operator new實(shí)際上總是以標(biāo)準(zhǔn)的C malloc()完成,雖然并沒(méi)有規(guī)定非得這么做不可。同樣,operator delete也總是以標(biāo)準(zhǔn)得C free()來(lái)實(shí)現(xiàn),不考慮異常處理的話他們類似下面的樣子:
extern void* operator new( size_t size )
{
if( size == 0 )
size = 1; // 這里保證像 new T[0] 這樣得語(yǔ)句也是可行的
void *last_alloc;
while( !(last_alloc = malloc( size )) )
{
if( _new_handler )
( *_new_handler )();
else
return 0;
}
return last_alloc;
}
extern void operator delete( void *ptr )
{
if(ptr) // 從這里可以看出,刪除一個(gè)空指針是安全的
free( (char*)ptr );
}
1. 分清operator new和new operator
全局函數(shù)operator new通常這樣聲明:
void * operator new(size_t size);
返回值類型是void*,表示其返回的是一個(gè)未經(jīng)處理(raw)的指針,指向未初始化的內(nèi)存。參數(shù)size_t確定分配多少內(nèi)存。你能增加額外的參數(shù)重載函數(shù)operator new,但是第一個(gè)參數(shù)類型必須是size_t。頭文件
void * operator new(size_t, void *location)
{
return location;
}
這初看上去有些陌生,但它卻是new操作符的一種常見(jiàn)重載方法,使用一個(gè)額外的變量buffer,當(dāng)new操作符隱含調(diào)用operator new函數(shù)時(shí),把這個(gè)變量傳遞給它。被調(diào)用的operator new函數(shù)除了持有強(qiáng)制的參數(shù)size_t外,還必須接受void*指針參數(shù),指向構(gòu)造對(duì)象占用的內(nèi)存空間。未被使用的(但是強(qiáng)制的)參數(shù)size_t沒(méi)有參數(shù)名字,以防止編譯器警告說(shuō)它未被使用。在使用placement new的情況下,調(diào)用者已經(jīng)獲得了指向內(nèi)存的指針,因?yàn)檎{(diào)用者知道對(duì)象應(yīng)該放在哪里。placement new需要做的就是返回傳遞給它的指針。
我們更經(jīng)常使用的new是new操作符(new operator),而非操作符new(operator new),如當(dāng)你使用new操作符構(gòu)建一個(gè)對(duì)象的時(shí)候,實(shí)際上做了兩件事情,一是調(diào)用operator new函數(shù)獲取內(nèi)存,二是調(diào)用對(duì)象的構(gòu)造函數(shù),如:
string *ps = new string("Hello, world!");
它完成與下面代碼相似的功能:
void *memory = operator new(sizeof(string)); // 為String對(duì)象得到未經(jīng)處理的內(nèi)存
call string::string("Hello, world!") on *memory; // 調(diào)用構(gòu)造函數(shù)初始化內(nèi)存中的對(duì)象
string *ps = static_cast
注意第二步中構(gòu)造函數(shù)的調(diào)用只能由編譯器完成,用戶是不允許這樣操作的,也就是說(shuō)如果你想建立一個(gè)堆對(duì)象就必須用new操作符,不能直接像上面一樣調(diào)用構(gòu)造函數(shù)來(lái)初始化堆對(duì)象。
new操作符(new operator)是編譯器內(nèi)置的,其行為被語(yǔ)言固定下來(lái),不受用戶控制。但是它們所調(diào)用的內(nèi)存分配函數(shù)也就是操作符new(operator new)則可以根據(jù)需要進(jìn)行重載。試著回顧new操作符(new operator)與操作符new(operator new)的關(guān)系,如果你想在堆上建立一個(gè)對(duì)象,應(yīng)該用new操作符。它既分配內(nèi)存又為對(duì)象調(diào)用構(gòu)造函數(shù)。如果你僅僅想分配內(nèi)存,就應(yīng)該調(diào)用operator new函數(shù),它不會(huì)調(diào)用構(gòu)造函數(shù)。如果你想定制自己獨(dú)有的內(nèi)存分配過(guò)程,你應(yīng)該重載全局的operator new函數(shù),然后使用new操作符,new操作符會(huì)調(diào)用你定制的operator new。如果你想在一塊已經(jīng)獲得指針的內(nèi)存里建立一個(gè)對(duì)象,應(yīng)該使用placement new。
最后需要記住的一點(diǎn)是,delete和new一樣具有以上的特性,只是需要注意的一點(diǎn)是delte操作符中是首先調(diào)用對(duì)象的析構(gòu)函數(shù),然后再調(diào)用operator delete函數(shù)的。
2. 針對(duì)數(shù)組的new[]和delete[]操作
建立數(shù)組時(shí)new操作符(new[])的行為與單個(gè)對(duì)象建立(new)有少許不同:
第一是內(nèi)存不再調(diào)用用operator new函數(shù)進(jìn)行分配,代替以operator new[]函數(shù)(常稱作array new)。它與operator new一樣能被重載,允許定制數(shù)組的內(nèi)存分配,就象定制單個(gè)對(duì)象內(nèi)存分配一樣。
第二個(gè)不同是new[]操作時(shí)調(diào)用構(gòu)造函數(shù)的數(shù)量。對(duì)于new[]而言,在數(shù)組里的每一個(gè)對(duì)象的構(gòu)造函數(shù)都必須被調(diào)用。
delete[]操作符的語(yǔ)義基本上和new[]相同,他們的實(shí)現(xiàn)類似這樣:
void * operator new[](size_t size)
{
cout << "new size of array in new[](): " << size << endl;
int *g =(int *) malloc(sizeof(size));
return g;
}
void operator delete[](void* p)
{
cout << "delete address of array pointer in delete[](): " << p << endl;
free(p);
}
3. operator new和delete函數(shù)的實(shí)現(xiàn)
operator new實(shí)際上總是以標(biāo)準(zhǔn)的C malloc()完成,雖然并沒(méi)有規(guī)定非得這么做不可。同樣,operator delete也總是以標(biāo)準(zhǔn)得C free()來(lái)實(shí)現(xiàn),不考慮異常處理的話他們類似下面的樣子:
extern void* operator new( size_t size )
{
if( size == 0 )
size = 1; // 這里保證像 new T[0] 這樣得語(yǔ)句也是可行的
void *last_alloc;
while( !(last_alloc = malloc( size )) )
{
if( _new_handler )
( *_new_handler )();
else
return 0;
}
return last_alloc;
}
extern void operator delete( void *ptr )
{
if(ptr) // 從這里可以看出,刪除一個(gè)空指針是安全的
free( (char*)ptr );
}