在嵌入式系統(tǒng)中使用C++的一個(gè)常見問題是內(nèi)存分配,即對(duì)new 和 delete 操作符的失控。
具有諷刺意味的是,問題的根源卻是C++對(duì)內(nèi)存的管理非常的容易而且安全。具體地說,當(dāng)一個(gè)對(duì)象被消除時(shí),它的析構(gòu)函數(shù)能夠安全的釋放所分配的內(nèi)存。這當(dāng)然是個(gè)好事情,但是這種使用的簡單性使得程序員們過度使用new 和 delete,而不注意在嵌入式C++環(huán)境中的因果關(guān)系。并且,在嵌入式系統(tǒng)中,由于內(nèi)存的限制,頻繁的動(dòng)態(tài)分配不定大小的內(nèi)存會(huì)引起很大的問題以及堆破碎的風(fēng)險(xiǎn)。
作為忠告,保守的使用內(nèi)存分配是嵌入式環(huán)境中的第一原則。
但當(dāng)你必須要使用new 和delete時(shí),你不得不控制C++中的內(nèi)存分配。你需要用一個(gè)全局的new 和delete來代替系統(tǒng)的內(nèi)存分配符,并且一個(gè)類一個(gè)類的重載new 和delete。
一個(gè)防止堆破碎的通用方法是從不同固定大小的內(nèi)存持中分配不同類型的對(duì)象。對(duì)每個(gè)類重載new 和delete就提供了這樣的控制。
重載全局的new 和delete 操作符
可以很容易地重載new 和 delete 操作符,如下所示:
void * operator new(size_t size)
{
void *p = malloc(size);
return (p);
}
void operator delete(void *p);
{
free(p);
}
這段代碼可以代替默認(rèn)的操作符來滿足內(nèi)存分配的請(qǐng)求。出于解釋C++的目的,我們也可以直接調(diào)用malloc() 和free()。
也可以對(duì)單個(gè)類的new 和 delete 操作符重載。這是你能靈活的控制對(duì)象的內(nèi)存分配。
class TestClass {
public:
void * operator new(size_t size);
void operator delete(void *p);
// .. other members here ...
};
void *TestClass::operator new(size_t size)
{
void *p = malloc(size); // Replace this with alternative allocator
return (p);
}
void TestClass::operator delete(void *p)
{
free(p); // Replace this with alternative de-allocator
}
所有TestClass 對(duì)象的內(nèi)存分配都采用這段代碼。更進(jìn)一步,任何從TestClass 繼承的類也都采用這一方式,除非它自己也重載了new 和 delete 操作符。通過重載new 和 delete 操作符的方法,你可以自由地采用不同的分配策略,從不同的內(nèi)存池中分配不同的類對(duì)象。
為單個(gè)的類重載 new[ ] 和 delete[ ] 必須小心對(duì)象數(shù)組的分配。你可能希望調(diào)用到被你重載過的new 和 delete 操作符,但并不如此。內(nèi)存的請(qǐng)求被定向到全局的new[ ]和delete[ ] 操作符,而這些內(nèi)存來自于系統(tǒng)堆。
C++將對(duì)象數(shù)組的內(nèi)存分配作為一個(gè)單獨(dú)的操作,而不同于單個(gè)對(duì)象的內(nèi)存分配。為了改變這種方式,你同樣需要重載new[ ] 和 delete[ ]操作符。
class TestClass {
public:
void * operator new[ ](size_t size);
void operator delete[ ](void *p);
// .. other members here ..
};
void *TestClass::operator new[ ](size_t size)
{
void *p = malloc(size);
return (p);
}
void TestClass::operator delete[ ](void *p)
{
free(p);
}
int main(void)
{
TestClass *p = new TestClass[10];
// ... etc ...
delete[ ] p;
}
但是注意:對(duì)于多數(shù)C++的實(shí)現(xiàn),new[]操作符中的個(gè)數(shù)參數(shù)是數(shù)組的大小加上額外的存儲(chǔ)對(duì)象數(shù)目的一些字節(jié)。在你的內(nèi)存分配機(jī)制重要考慮的這一點(diǎn)。你應(yīng)該盡量避免分配對(duì)象數(shù)組,從而使你的內(nèi)存分配策略簡單。
具有諷刺意味的是,問題的根源卻是C++對(duì)內(nèi)存的管理非常的容易而且安全。具體地說,當(dāng)一個(gè)對(duì)象被消除時(shí),它的析構(gòu)函數(shù)能夠安全的釋放所分配的內(nèi)存。這當(dāng)然是個(gè)好事情,但是這種使用的簡單性使得程序員們過度使用new 和 delete,而不注意在嵌入式C++環(huán)境中的因果關(guān)系。并且,在嵌入式系統(tǒng)中,由于內(nèi)存的限制,頻繁的動(dòng)態(tài)分配不定大小的內(nèi)存會(huì)引起很大的問題以及堆破碎的風(fēng)險(xiǎn)。
作為忠告,保守的使用內(nèi)存分配是嵌入式環(huán)境中的第一原則。
但當(dāng)你必須要使用new 和delete時(shí),你不得不控制C++中的內(nèi)存分配。你需要用一個(gè)全局的new 和delete來代替系統(tǒng)的內(nèi)存分配符,并且一個(gè)類一個(gè)類的重載new 和delete。
一個(gè)防止堆破碎的通用方法是從不同固定大小的內(nèi)存持中分配不同類型的對(duì)象。對(duì)每個(gè)類重載new 和delete就提供了這樣的控制。
重載全局的new 和delete 操作符
可以很容易地重載new 和 delete 操作符,如下所示:
void * operator new(size_t size)
{
void *p = malloc(size);
return (p);
}
void operator delete(void *p);
{
free(p);
}
這段代碼可以代替默認(rèn)的操作符來滿足內(nèi)存分配的請(qǐng)求。出于解釋C++的目的,我們也可以直接調(diào)用malloc() 和free()。
也可以對(duì)單個(gè)類的new 和 delete 操作符重載。這是你能靈活的控制對(duì)象的內(nèi)存分配。
class TestClass {
public:
void * operator new(size_t size);
void operator delete(void *p);
// .. other members here ...
};
void *TestClass::operator new(size_t size)
{
void *p = malloc(size); // Replace this with alternative allocator
return (p);
}
void TestClass::operator delete(void *p)
{
free(p); // Replace this with alternative de-allocator
}
所有TestClass 對(duì)象的內(nèi)存分配都采用這段代碼。更進(jìn)一步,任何從TestClass 繼承的類也都采用這一方式,除非它自己也重載了new 和 delete 操作符。通過重載new 和 delete 操作符的方法,你可以自由地采用不同的分配策略,從不同的內(nèi)存池中分配不同的類對(duì)象。
為單個(gè)的類重載 new[ ] 和 delete[ ] 必須小心對(duì)象數(shù)組的分配。你可能希望調(diào)用到被你重載過的new 和 delete 操作符,但并不如此。內(nèi)存的請(qǐng)求被定向到全局的new[ ]和delete[ ] 操作符,而這些內(nèi)存來自于系統(tǒng)堆。
C++將對(duì)象數(shù)組的內(nèi)存分配作為一個(gè)單獨(dú)的操作,而不同于單個(gè)對(duì)象的內(nèi)存分配。為了改變這種方式,你同樣需要重載new[ ] 和 delete[ ]操作符。
class TestClass {
public:
void * operator new[ ](size_t size);
void operator delete[ ](void *p);
// .. other members here ..
};
void *TestClass::operator new[ ](size_t size)
{
void *p = malloc(size);
return (p);
}
void TestClass::operator delete[ ](void *p)
{
free(p);
}
int main(void)
{
TestClass *p = new TestClass[10];
// ... etc ...
delete[ ] p;
}
但是注意:對(duì)于多數(shù)C++的實(shí)現(xiàn),new[]操作符中的個(gè)數(shù)參數(shù)是數(shù)組的大小加上額外的存儲(chǔ)對(duì)象數(shù)目的一些字節(jié)。在你的內(nèi)存分配機(jī)制重要考慮的這一點(diǎn)。你應(yīng)該盡量避免分配對(duì)象數(shù)組,從而使你的內(nèi)存分配策略簡單。