標籤:

C++new運算符調用operator new 分配內存後, 構造函數調用及指針類型的轉換在哪裡完成?

C語言中的 分配內存 類型轉換都是顯示指定的

struct tmp* p=(struct tmp*)malloc(sizeof(struct tmp));

c++ 中 new 運算符 直接 要分配空間 並返回對應的類型指針空間

new 運算符 調用的是 operator new 函數

在源碼中這個函數中跟C語言一樣也是用malloc分配的內存空間並返回 void* 內存空間

對象的構造函數調用以及指針類型的轉換在哪裡完成?都是編譯完成的?是怎麼樣完成的,,,內存類型轉換是不是跟C語言的一樣.

比如:類Foo

Foo *f = new Foo;先調用 operator new 分配內存空間 void* 類型 後續的調用構造函數以及類型轉換 是在什麼時候及如何完成的.。


是在編譯器內部做的,而不是在標準庫里。

我舉一個很簡單的例子

struct foo
{
foo() {}
int x;
};

int main()
{
auto f = new foo;
}

我們看Clang的中間語言文件, 為了闡述的方便,我編譯的時候使用了-fno-exceptions 關閉了異常。

; Function Attrs: norecurse nounwind ssp uwtable
define i32 @main() #0 {
entry:
%f = alloca %struct.foo*, align 8
%call = call i8* @_Znwm(i64 4) #3
%0 = bitcast i8* %call to %struct.foo*
call void @_ZN3fooC1Ev(%struct.foo* %0)
store %struct.foo* %0, %struct.foo** %f, align 8
ret i32 0
}

; Function Attrs: nobuiltin
declare noalias i8* @_Znwm(i64) #1

; Function Attrs: nounwind ssp uwtable
define linkonce_odr void @_ZN3fooC1Ev(%struct.foo* %this) unnamed_addr #2 align 2 {
entry:
%this.addr = alloca %struct.foo*, align 8
store %struct.foo* %this, %struct.foo** %this.addr, align 8
%this1 = load %struct.foo*, %struct.foo** %this.addr, align 8
call void @_ZN3fooC2Ev(%struct.foo* %this1)
ret void
}

; Function Attrs: nounwind ssp uwtable
define linkonce_odr void @_ZN3fooC2Ev(%struct.foo* %this) unnamed_addr #2 align 2 {
entry:
%this.addr = alloca %struct.foo*, align 8
store %struct.foo* %this, %struct.foo** %this.addr, align 8
%this1 = load %struct.foo*, %struct.foo** %this.addr, align 8
ret void
}

這裡的_Znwm是標準庫來的,返回類型是i8*,對應到了C++裡面的void*. 你說的類型轉換對應於 %0 = bitcast i8* %call to %struct.foo*. 構造函數的調用則在這 call void @_ZN3fooC1Ev(%struct.foo* %0)。 你可能會好奇為什麼會有兩個構造函數,C1和C2,但是很遺憾,我不太想講-_-||,你只需要知道這是ABI規定的即可,普通C++開發程序員沒有任何必要需要知道構造函數為什麼有C1和C2。

若你打開Clang的ExprCXX.h,就能找到new的相關實現,即CXXNewExpr,具體的參考API與實現可以在這裡獲得:clang: clang::CXXNewExpr Class Reference。 若你對其中的BitCast的發生,函數的調用感興趣,可以參考CodeGen部分,如clang: CGExprCXX.cpp Source File:CodeGenFunction::EmitCXXNewExpr


你概念里的那個「指針類型的轉換」,根本不需要任何運行時操作。真正需要「干一些事情」的指針類型轉換,只有static_cast、dynamic_cast不同的類。

這體現了這類語言的一個難點:不同的行為分別在宏替換時、編譯時、鏈接時、運行時執行,極大地增加了新手需要接觸的概念數量。C++由於增加了類的類型轉換,又進一步惡化了這個問題。


在vs2015中,一條new表達式,在編譯後會生成這樣的代碼

根據類型大小調用new申請內存

if(申請成功)

以獲得的內存地址作為參數調用構造函數


一般是編譯器會將new表達式解析為三條語句。分配內存(operator new),指針轉換,調用構造函數。


推薦閱讀:

有哪些較好的 C 語言程序源碼可供新手臨摹參考?
新手入門c語言應該下載那個軟體?
寫庫函數供他人用的原理是什麼?
C語言編譯中,如何查看定義了哪些宏?
如果要寫一個類似於現在Word的軟體,僅用C語言或者C++,可以完成嗎?

TAG:C編程語言 | C | CC |