程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 周全解析C++中的new,operator new與placement new

周全解析C++中的new,operator new與placement new

編輯:關於C++

周全解析C++中的new,operator new與placement new。本站提示廣大學習愛好者:(周全解析C++中的new,operator new與placement new)文章只能為提供參考,不一定能成為您想要的結果。以下是周全解析C++中的new,operator new與placement new正文


new operator/delete operator就是new和delete操作符,而operator new/operator delete是函數。

new operator
(1)挪用operator new分派足夠的空間,並挪用相干對象的結構函數
(2)弗成以被重載

operator new
(1)只分派所請求的空間,不挪用相干對象的結構函數。當沒法知足所請求分派的空間時,則
        ->假如有new_handler,則挪用new_handler,不然
        ->假如沒請求不拋出異常(以nothrow參數表達),則履行bad_alloc異常,不然
        ->前往0
(2)可以被重載
(3)重載時,前往類型必需聲明為void*
(4)重載時,第一個參數類型必需為表達請求分派空間的年夜小(字節),類型為size_t
(5)重載時,可以帶其它參數

delete 與 delete operator相似。

#include<iostream>
#include<string>
using namespace std;

class X
{
public:
 X() {cout<<"constructor of X"<<endl;}
 ~X() {cout<<"destructor of X"<<endl;}
 void* operator new(size_t size,string str)
 {
   cout<<"operator new size"<<size<<"with string"<<str<<endl;
   return ::operator new(size);
 }
 void operator delete(void* pointee)
 {
   cout<<"operator delete"<<endl;
   ::operator delete(pointee);
 }
private:
 int num;
}

int main()
{
  X *px=new("A new class") X;
  delete px;
  return 0;
}

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和operator delete?
謎底平日是:為了效力。缺省的operator new和operator delete具有異常好的通用性,它的這類靈巧性也使得在某些特定的場所下,可以進一步改良它的機能。特別在那些須要靜態分派年夜量的但很小的對象的運用法式裡,情形更是如斯。詳細可參考《Effective C++》中的第二章內存治理。

Placement new的寄義
placement new 是重載operator new 的一個尺度、全局的版本,它不克不及夠被自界說的版本取代(不像通俗版本的operator new和operator delete可以或許被調換)。
void *operator new( size_t, void * p ) throw() { return p; }
placement new的履行疏忽了size_t參數,只返還第二個參數。其成果是許可用戶把一個對象放到一個特定的處所,到達挪用結構函數的後果。和其他通俗的new分歧的是,它在括號裡多了別的一個參數。好比:

Widget * p = new Widget;                    //ordinary new
pi = new (ptr) int; pi = new (ptr) int;     //placement new

括號裡的參數ptr是一個指針,它指向一個內存緩沖器,placement new將在這個緩沖器上分派一個對象。Placement new的前往值是這個被結構對象的地址(好比括號中的傳遞參數)。placement new重要實用於:在對時光請求異常高的運用法式中,由於這些法式分派的時光是肯定的;長時光運轉而不被打斷的法式;和履行一個渣滓搜集器 (garbage collector)。

new 、operator new 和 placement new 差別
(1)new :不克不及被重載,其行動老是分歧的。它先挪用operator new分派內存,然後挪用結構函數初始化那段內存。

new 操作符的履行進程:
1. 挪用operator new分派內存 ;
2. 挪用結構函數生成類對象;
3. 前往響應指針。

(2)operator new:要完成分歧的內存分派行動,應當重載operator new,而不是new。
operator new就像operator + 一樣,是可以重載的。假如類中沒有重載operator new,那末挪用的就是全局的::operator new來完成堆的分派。同理,operator new[]、operator delete、operator delete[]也是可以重載的。

(3)placement new:只是operator new重載的一個版本。它其實不分派內存,只是前往指向曾經分派好的某段內存的一個指針。是以不克不及刪除它,但須要挪用對象的析構函數。

假如你想在曾經分派的內存中創立一個對象,應用new時行欠亨的。也就是說placement new許可你在一個曾經分派好的內存中(棧或許堆中)結構一個新的對象。原型中void* p現實上就是指向一個曾經分派好的內存緩沖區的的首地址。

Placement new 存在的來由

1.用placement new 處理buffer的成績
成績描寫:用new分派的數組緩沖時,因為挪用了默許結構函數,是以履行效力上欠安。若沒有默許結構函數則會產生編譯時毛病。假如你想在預分派的內存上創立對象,用缺省的new操作符是行欠亨的。要處理這個成績,你可以用placement new結構。它許可你結構一個新對象到預分派的內存上。

2.增年夜時空效力的成績
應用new操作符分派內存須要在堆中查找足夠年夜的殘剩空間,明顯這個操作速度是很慢的,並且有能夠湧現沒法分派內存的異常(空間不敷)。placement new便可以處理這個成績。我們結構對象都是在一個事後預備好了的內存緩沖區中停止,不須要查找內存,內存分派的時光是常數;並且不會湧現在法式運轉半途湧現內存缺乏的異常。所以,placement new異常合適那些對時光請求比擬高,長時光運轉不願望被打斷的運用法式。

Placement new應用步調
在許多情形下,placement new的應用辦法和其他通俗的new有所分歧。這裡供給了它的應用步調。

第一步  緩存提早分派

有三種方法:

1.為了包管經由過程placement new應用的緩存區的memory alignment(內存隊列)准確預備,應用通俗的new來分派它:在堆長進行分派
class Task ;
char * buff = new [sizeof(Task)]; //分派內存
(請留意auto或許static內存並不是都准確地為每個對象類型分列,所以,你將不克不及以placement new應用它們。)

2.在棧長進行分派
class Task ;
char buf[N*sizeof(Task)]; //分派內存

3.還有一種方法,就是直接經由過程地址來應用。(必需是成心義的地址)
void* buf = reinterpret_cast<void*> (0xF00F);

第二步:對象的分派

在適才已分派的緩存區挪用placement new來結構一個對象。
Task *ptask = new (buf) Task

第三步:應用

依照通俗方法應用分派的對象:

ptask->memberfunction();

ptask-> member;

//...

第四步:對象的析構

一旦你應用完這個對象,你必需挪用它的析構函數來撲滅它。依照上面的方法挪用析構函數:
ptask->~Task(); //挪用內在的析構函數

第五步:釋放

你可以重復應用緩存並給它分派一個新的對象(反復步調2,3,4)假如你不盤算再次應用這個緩存,你可以象如許釋放它:delete [] buf;

跳過任何步調便可能招致運轉時光的瓦解,內存洩漏,和其它的意想不到的情形。假如你確切須要應用placement new,請賣力遵守以上的步調。

#include <iostream>
using namespace std;

class X
{
public:
    X() { cout<<"constructor of X"<<endl; }
    ~X() { cout<<"destructor of X"<<endl;}

    void SetNum(int n)
    {
        num = n;
    }

    int GetNum()
    {
        return num;
    }

private:
    int num;
};

int main()
{
    char* buf = new char[sizeof(X)];
    X *px = new(buf) X;
    px->SetNum(10);
    cout<<px->GetNum()<<endl;
    px->~X();
    delete []buf;

    return 0;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved