日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

Effective C++ 读书笔记(八)

發布時間:2023/12/13 c/c++ 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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拋出異常以反映一個未獲滿足的內存需求之前,它會先調用一個客戶指定的錯誤處理函數,客戶必須調用set_new_handler設定。

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的合理替換時機

條款51:編寫new和delete時需固守常規

實現一致性operator new必得返回正確的值,內存不足時必得調用new-handling函數,必須有對付0內存需求的準備。operator new返回值十分單純,如果它有能力供應客戶申請的內存,就返回一個指針指向那塊內存,如果沒有那個能力,拋出一個bad_alloc異常。

???????? 然而也不是非常單純,因為operator new實際上不只一次嘗試分配內存,并在每次失敗后調用new-handling函數。這里假設new-handling函數能夠做某些動作將內存釋放出來,只有當new-handling指針為null時,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 一個指針指向分配的內存

???????? new_handler? globalHandler? =? set_new_handler(0);

???????? set_new_handler( globalHandler);

???????? if( globalHandler ) (*globalHandler)();

???????? else throw std::bad_alloc();

}

}

?

許多人沒有考慮operator new成員函數會被derived class繼承。一旦被繼承base class的operator new被調用以分配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; //調用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接受的參數除了一定會有的那個size_t之外還有其他,這便是所謂的placement new。眾多placement new版本中特別有用的一個是“接受一個指針指向對象該被構造之處”,那樣的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( );

???????? …

};

上述代碼存在微妙的內存泄漏。它在動態創建一個Widget時將相關分配信息志記于cerr:

???????? Widget* pw = new (std::cerr) Widget;

如果內存分配成功,但Widget構造函數拋出異常,運行系統有責任取消operator new的分配。運行系統會尋找參數個數和類型都 與operator new相同 的某個operator delete,如果找到,那就是它的調用對象。

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;//調用正常的operator delete,而非 placement版本。

因此,我們必須同時提供一個正常的operator delete和一個placement版本(參數必須和operator new一樣)。只要這樣做,就不會有難以察覺的內存泄漏了。

?

另外,考慮到成員函數的名稱會掩蓋其外因作用域中的相同名稱,例如:

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,內含所有正常形式的new 和 delete。

?

若想以自定義形式擴展標準形式的客戶,可利用繼承機制及using聲明式取得標準形式。

?

轉載于:https://www.cnblogs.com/dachengxu/archive/2012/11/21/2781669.html

總結

以上是生活随笔為你收集整理的Effective C++ 读书笔记(八)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。