Effective C++ 读书笔记(八)
8 定制new和delete
條款49:了解new-handler的行為
new_handler ?set_new_handler (new_handler new_p) ?throw();
Sets ?new_p ?as the new handler function, ?the old one is returned.
operator new拋出異常以反映一個未獲滿足的內(nèi)存需求之前,它會先調(diào)用一個客戶指定的錯誤處理函數(shù),客戶必須調(diào)用set_new_handler設(shè)定。
class NewHandlerHolder{
explicit NewHandlerHolder (std::new_handler? nh):handler(nh){}
~NewHandlerHolder(){std::set_new_handler(handler);}
private:
???????? std::new_handler? handler;
};
?
class Widget{
public:
???????? static? std::new_handler set_new_handler(std::new_handler? p) throw();
???????? static? void? *operator new(std::size_t? size)throw(std::bad_alloc);
private:
???????? static? std::new_handler? currentHandler;
};
std::new_handler ?Widget::currentHandler = 0;
std::new_handler? Widget::set_new_handler (std::new_handler? p) throw
{
std::new_handler? oldHandler = currentHandler;
currentHandler? = p;
return oldHandler;
}
void*? Widget:: operator new (std::size_t? size) throw
{
NewHandlerHolder h( std::set_new_handler(currentHandler) );
return ::operator new(size);
}
?
使用:
void outOfMem();
Widget::set_new_handler(outOfMem);
Widget* pw1 = new Widget;
?
條款50:了解new和delete的合理替換時(shí)機(jī)
略
條款51:編寫new和delete時(shí)需固守常規(guī)
實(shí)現(xiàn)一致性operator new必得返回正確的值,內(nèi)存不足時(shí)必得調(diào)用new-handling函數(shù),必須有對付0內(nèi)存需求的準(zhǔn)備。operator new返回值十分單純,如果它有能力供應(yīng)客戶申請的內(nèi)存,就返回一個指針指向那塊內(nèi)存,如果沒有那個能力,拋出一個bad_alloc異常。
???????? 然而也不是非常單純,因?yàn)閛perator new實(shí)際上不只一次嘗試分配內(nèi)存,并在每次失敗后調(diào)用new-handling函數(shù)。這里假設(shè)new-handling函數(shù)能夠做某些動作將內(nèi)存釋放出來,只有當(dāng)new-handling指針為null時(shí),operator new才會拋出異常。
下面是non-member operator new?偽碼:
void * operator new(std::size_t? size) throw(std::bad_alloc)
{
???????? using namespace std;
???????? if(size == 0) size =1;
???????? while(true){
???????? 嘗試分配size bytes;
???????? if 分配成功
?????????????????? return 一個指針指向分配的內(nèi)存
???????? new_handler? globalHandler? =? set_new_handler(0);
???????? set_new_handler( globalHandler);
???????? if( globalHandler ) (*globalHandler)();
???????? else throw std::bad_alloc();
}
}
?
許多人沒有考慮operator new成員函數(shù)會被derived class繼承。一旦被繼承base class的operator new被調(diào)用以分配derived class對象。例如:
class Base{
public:? static void * operator new(std::size_t? size) throw(std::bad_alloc);
???????? …
}
class Derived: public Base { … }
Derived* p = new Derived; //調(diào)用Base::operator new
解決方法:
void * Base::operator new(std::size_t? size) throw(std::bad_alloc)
{
???????? if(size != sizeof(Base) ) return ::operator new(size);
???????? …
}
?
條款52:寫了placement new也要寫placement delete
如果operator new接受的參數(shù)除了一定會有的那個size_t之外還有其他,這便是所謂的placement new。眾多placement new版本中特別有用的一個是“接受一個指針指向?qū)ο笤摫粯?gòu)造之處”,那樣的operator new聲明如下:
???????? void * operator new(std::size_t, void *)throw();
對于以下代碼:
class Widget{
public:
???????? static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
???????? static void? operator delete(void* pMemory, std::size_t size)throw( );
???????? …
};
上述代碼存在微妙的內(nèi)存泄漏。它在動態(tài)創(chuàng)建一個Widget時(shí)將相關(guān)分配信息志記于cerr:
???????? Widget* pw = new (std::cerr) Widget;
如果內(nèi)存分配成功,但Widget構(gòu)造函數(shù)拋出異常,運(yùn)行系統(tǒng)有責(zé)任取消operator new的分配。運(yùn)行系統(tǒng)會尋找參數(shù)個數(shù)和類型都 與operator new相同 的某個operator delete,如果找到,那就是它的調(diào)用對象。
class Widget{
public:
???????? static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
???????? static void? operator delete(std::size_t size, std::ostream& logStream)throw( );
static void? operator delete(void* pMemory) throw( );
???????? …
};
Widget* pw = new (std::cerr) Widget; //不再泄漏
但 delete pw;//調(diào)用正常的operator delete,而非 placement版本。
因此,我們必須同時(shí)提供一個正常的operator delete和一個placement版本(參數(shù)必須和operator new一樣)。只要這樣做,就不會有難以察覺的內(nèi)存泄漏了。
?
另外,考慮到成員函數(shù)的名稱會掩蓋其外因作用域中的相同名稱,例如:
class Base{
public:
???????? static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
???????? …
};
Base* pb = new Base; //error,掩蓋
Base* pb = new (std::cerr) Base; //OK
同理,derived classes 中的operator new掩蓋global版本和繼承版。
class Derived: public Base{
public:
???????? static void* operator new(std::size_t size) throw(std::bad_alloc);
???????? …
};
Derived* pd = new (std::clog) Derived; //error,掩蓋
Derived* pd = new Derived;
解決辦法:建立一個base class,內(nèi)含所有正常形式的new 和 delete。
?
若想以自定義形式擴(kuò)展標(biāo)準(zhǔn)形式的客戶,可利用繼承機(jī)制及using聲明式取得標(biāo)準(zhǔn)形式。
?
轉(zhuǎn)載于:https://www.cnblogs.com/dachengxu/archive/2012/11/21/2781669.html
總結(jié)
以上是生活随笔為你收集整理的Effective C++ 读书笔记(八)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Threejs模仿实现滴滴官网首页地球动
- 下一篇: 【VC6.0】getline需要输入2次