C++ new、delete(new[]、delete[])操作符重載須要留意的成績。本站提示廣大學習愛好者:(C++ new、delete(new[]、delete[])操作符重載須要留意的成績)文章只能為提供參考,不一定能成為您想要的結果。以下是C++ new、delete(new[]、delete[])操作符重載須要留意的成績正文
new、delete(new[]、delete[])操作符的重載須要留意:
1.重載的 new、delete(或許 new[]、delete[])操作符必需是類的靜態成員函數(為何必需是靜態成員函數,這很好懂得,由於 new 操作符被挪用的時刻,對象還未構建)或許是全局函數,函數的原型以下:
void* operator new(size_t size) throw(std::bad_alloc);
// 這裡的 size 為分派的內存的總年夜小
void* operator new[](size_t size) throw(std::bad_alloc);
void operator delete(void* p) throw();
void operator delete[](void* p) throw();
void operator delete(void* p, size_t size) throw();
// 差別於 new[] 的參數 size,這裡的 size 並不是釋放的內存的總年夜小
void operator delete[](void* p, size_t size) throw();
別的,我們可使用分歧的參數來重載 new、delete(或許 new[]、delete[])操作符,例如:
// 第一個參數仍為 size_t
void* operator new(size_t size, const char* file, int line);
// 此操作符的應用
string* str = new(__FILE__, __LINE__) string;
重載全局的 new、delete(或許 new[]、delete[])操作符會轉變一切默許分派行動(包含某個類的分派行動),是以必需當心應用,假如兩個庫都 new 等停止了全局重載,那末就會湧現鏈接毛病(duplicated symbol link error)。而在類中界說的 new、delete(或許 new[]、delete[])操作符只會影響到本類和派生類。
許多人完整沒無意識到 operator new、operator delete、operator new[]、operator delete[] 成員函數會被繼續(固然它們是靜態函數)。有些時刻,我們只想為指定的類設置自界說的 operator new 成員函數,而不願望影響到子類的任務。《Effective C++ Third Edition》供給了以下的計劃:
void * Base::operator new(std::size_t size) throw(std::bad_alloc)
{
// 假如年夜小不為基類年夜小
if (size != sizeof(Base))
// 挪用尺度的 new 操作符
return ::operator new(size);
自界說年夜小為基類年夜小的分派處置
}
如許處置的一個條件是:以為子類的年夜小必定年夜於父類。
關於 operator new[] 來講,我們很難經由過程下面的方法檢討究竟是父類照樣子類挪用了操作符。經由過程 operator new[] 操作符的參數,我們沒法得知分派的元素的個數,沒法得知分派的每一個元素的年夜小。operator new[] 的參數 size_t 注解的內存分派的年夜小能夠年夜於須要分派的元素的內存年夜小之和,由於靜態內存分派能夠會分派額定的空間來保留數組元素的個數。
2.兼容默許的 new、delete 的毛病處置方法
這不是個很簡略的事(具體參考《Effective C++ Third Edition》 Item 51)。operator new 平日如許編寫:
// 這裡並沒有斟酌多線程拜訪的情形
void* operator new(std::size_t size) throw(std::bad_alloc)
{
using namespace std;
// size == 0 時 new 也必需前往一個正當的指針
if (size == 0)
size = 1;
while (true) {
測驗考試停止內存的分派
if (內存分派勝利)
return (勝利分派的內存的地址);
// 內存分派掉敗時,查找以後的 new-handling function
// 由於沒有直接獲得到 new-handling function 的方法,是以只能這麼做
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
// 假如存在 new-handling function 則挪用
if (globalHandler) (*globalHandler)();
// 不存在 new-handling function 則拋出異常
else throw std::bad_alloc();
}
}
這一些方面是我們須要留意的:operator new 可以接收 size 為 0 的內存分派且前往一個有用的指針;假如存在 new-handling function 那末在內存分派掉敗時會挪用它而且再次測驗考試內存分派;假如不存在 new-handling function 掉敗時拋出 bad_alloc 異常。
要留意的是,一旦設置了 new-handling function 內存分派就會無窮輪回停止下去,為了不無窮輪回的產生,new-handling function 必需做以下幾件事中的一件(具體參考《Effective C++ Third Edition》 Item 49):讓有更多內存可用、設置另外一個能施展感化的 new-handler、刪除以後的 new handler、拋出一個異常(bad_alloc 或許繼續於 bad_alloc)、直接挪用 abort() 或許 exit() 等函數。
關於 operator delete 的異常處置就簡略一些,只須要包管可以或許平安的 delete 空指針便可:
void operator delete(void *rawMemory) throw()
{
// 操作符可以接收空指針
if (rawMemory == 0) return;
釋放內存
}
多態的成績(具體參考《ISO/IEC 14882》)
後面談到了 new、delete(new[]、delete[])操作符的繼續,這裡額定評論辯論一下多態的成績,明顯我們只須要評論辯論 delete、delete[] 操作符:
struct B {
virtual ~B();
void operator delete(void*, size_t);
};
struct D : B {
void operator delete(void*);
};
void f()
{
B* bp = new D;
delete bp; //1: uses D::operator delete(void*)
}
經由過程下面的例子,我們可以看到,delete 時准確的挪用了 D 的 operator delete 操作符。然則異樣的,關於 delete[] 操作符任務就不正常了(由於關於 delete[] 操作符的檢討是靜態的):
struct B {
virtual ~B();
void operator delete[](void*, size_t);
};
struct D : B {
void operator delete[](void*, size_t);
};
void f(int i)
{
D* dp = new D[i];
delete [] dp; //uses D::operator delete[](void*, size_t)
B* bp = new D[i];
delete[] bp; //undefined behavior
}