operator new 與 new operator

轉載一篇 關於new的文章

 

operator new與new operator 收藏

C++中的operator new與new operator,看上去挺像的兩姐妹,卻有天壤之別。

operator new

(1) 只分配所要求的空間,不調用相關對象的構造函數。當無法滿足所要求分配的空間時,則

        ->如果有new_handler,則調用new_handler,否則

        ->如果沒要求不拋出異常(以nothrow參數表達),則執行bad_alloc異常,否則

        ->返回0

(2) 可以被重載

(3) 重載時,返回類型必須聲明爲void*

(4) 重載時,第一個參數類型必須爲表達要求分配空間的大小(字節),類型爲size_t

(5) 重載時,可以帶其它參數

new operator

(1) 調用operator new分配足夠的空間,並調用相關對象的構造函數

(2) 不可以被重載

相應地,operator delete與delete operator有相似的特性。

舉個例子

class X
{
public:
…………
    static void* operator new(size_t size)
{
    return ::operator new(size);
}
static void operator delete(void* pointee)
{
    ::operator delete(pointee);
}
…………
};
X* px = new X();

該行代碼中的new爲new operator,它將調用類X中的operator new,爲該類的對象分配空間,然後調用當前實例的構造函數。

delete px;

該行代碼中的delete爲delete operator,它將調用該實例的析構函數,然後調用類X中的operator delete,以釋放該實例佔用的空間。

new operator與delete operator的行爲是不能夠也不應該被改變,這是C++標準作出的承諾。而operator new與operator delete和C語言中的malloc與free對應,只負責分配及釋放空間。但使用operator new分配的空間必須使用operator delete來釋放,而不能使用free,因爲它們對內存使用的登記方式不同。反過來亦是一樣。

你可以重載operator new和operator delete以實現對內存管理的不同要求,但你不能重載new operator或delete operator以改變它們的行爲。

當重載operator new時,可以提供更多的參數,在new一個對象時,通過在關鍵字new後的括號傳遞額外的參數。比如以下的類

class A
{
public:
    …………
    static void* operator new(size_t size, const string& example)
{
    cout << example << endl;
    return ::operator new(size);
}
…………
};
A* pa = new (“This will be printed out in operator new”) A();

新標準的C++允許以這樣的方式傳遞一個名爲nothrow的參數,以表明當爲該對象分配空間失敗時,不拋出異常,而是返回0,以兼容舊標準new的行爲。比如

class B {};
B* pb = new (nothrow) B();

當然這隻能對那些使用默認operator new操作符的類。對已經重載了operator new的類(比如上面的X和A),如果不聲明能接受nothrow參數,自然無法享受C++標準帶來的禮物。

 

operator new的六種重載形式

當寫出
p = new P();
這樣的代碼的時候, 實際上有兩步操作, 首先分配內存,
然後在分配好的內存之上初始化類成員.
第二步是有構造函數完成的, 第一步就是new函數的工作.
全局的new有六種重載形式,
void *operator new(std::size_t count)
    throw(std::bad_alloc);             //一般的版本
void *operator new(std::size_t count,  //兼容早版本的new
    const std::nothrow_t&) throw();    //內存分配失敗不會拋出異常
void *operator new(std::size_t count, void *ptr) throw();
                                       //placement版本
void *operator new[](std::size_t count)  //
    throw(std::bad_alloc);
void *operator new[](std::size_t count,  //
    const std::nothrow_t&) throw();
void *operator new[](std::size_t count, void *ptr) throw();
所以, 剛纔的用法, 就是使用new函數的一種重載形式.
如果A這個對象以同樣實行重載了new函數的化, 作爲成員函數
會被優先調用.
C++的各種new簡介
1.new T
第一種new最簡單,調用類的(如果重載了的話)或者全局的operator new分配空間,然後用
類型後面列的參數來調用構造函數,用法是
new TypeName(initial_args_list). 如果沒有參數,括號一般可以省略.例如
int *p=new int;
int *p=new int(10);
int *p=new foo("hello");
通過調用delete來銷燬:
delete p;
2. new T[]
這種new用來創建一個動態的對象數組,他會調用對象的operator new[]來分配內存(如果
沒有則調用operator new,搜索順序同上),然後調用對象的默認構造函數初始化每個對象
用法:
new TypeName[num_of_objects];
例如
int *p= new int[10];
銷燬時使用operator delete[]
3.new()T 和new() T[]
這是個帶參數的new,這種形式的new會調用operator new(size_t,OtherType)來分配內存
這裏的OtherType要和new括號裏的參數的類型兼容,
這種語法通常用來在某個特定的地址構件對象,稱爲placement new,前提是operator new
(size_t,void*)已經定義,通常編譯器已經提供了一個實現,包含<new>頭文件即可,這個
實現只是簡單的把參數的指定的地址返回,因而new()運算符就會在括號裏的地址上創建
對象
需要說明的是,第二個參數不是一定要是void*,可以識別的合法類型,這時候由C++的重載
機制來決定調用那個operator new
當然,我們可以提供自己的operator new(size_,Type),來決定new的行爲,比如
char data[1000][sizeof(foo)];
inline void* operator new(size_t ,int n)
{
        return data[n];
}
就可以使用這樣有趣的語法來創建對象:
foo *p=new(6) foo(); //把對象創建在data的第六個單元上
的確很有意思
標準庫還提供了一個nothrow的實現:
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();
就可以實現調用new失敗時不拋出異常
new(nothrow) int(10);
// nothrow 是std::nothrow_t的一個實例
placement new 創建的對象不能直接delete來銷燬,而是要調用對象的析夠函數來銷燬對
象,至於對象所佔的內存如何處理,要看這塊內存的具體來源
4. operator new(size_t)
這個的運算符分配參數指定大小的內存並返回首地址,可以爲自定義的類重載這個運算符,
方法就是在類裏面聲明加上
void *operator new(size_t size)
{
        //在這裏分配內存並返回其地址
}
無論是否聲明,類裏面重載的各種operator new和operator delete都是具有static屬性的
一般不需要直接調用operator new,除非直接分配原始內存(這一點類似於C的malloc)
在衝突的情況下要調用全局的operator加上::作用域運算符:
::operator new(1000); // 分配1000個字節
返回的內存需要回收的話,調用對應的operator delete
5.operator new[](size_t)
這個也是分配內存,,只不過是專門針對數組,也就是new T[]這種形式,當然,需要時可以
顯式調用
6.operator new(size_t size, OtherType other_value)
和operator new[](size_t size, OtherType other_value)
參見上面的new()
需要強調的是,new用來創建對象並分配內存,它的行爲是不可改變的,可以改變的是各種
operator new,我們就可以通過重載operator new來實現我們的內存分配方案.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章