2010-08-01 75 views
2

給出一個指向原始內存「blob」的空指針,有兩種方法在它上面寫入內容。在原始內存中寫入非類型文件

第一種方法是使用放置新的。這種方法具有在我們處理類類型時自動調用ctor的優點。但是,當我處理非班級類型時,是否更好地做一個演員?我想它可能會更快。

(pLocation是一個空指針到的存儲器中的二進制大對象

// ----- Is this better ----- 
*reinterpret_cast<char*>(pLocation) = pattern; 

// ----- Or is this better ----- 
::new(pLocation) char(pattern); 
+0

不確定你想在這裏實現什麼,但'pattern'不會被複制到第一個示例中的'pLocation' - 你可以將它替換爲'pLocation = pattern;'如果你只是看用於指針分配。 – adamk 2010-08-01 07:43:03

+2

模式是字符。它將被複制到pLocation所指向的任何位置,代碼將按照預期編譯和工作。在這種情況下,兩種說法都是相同的。 – aCuria 2010-08-01 07:56:28

+1

在這兩種情況下,請謹慎對待pLocation是否與您的平臺上的任何字邊界限制保持一致。例如,你可能能夠在任何地方放置一個'char',但你可能無法在任何地方放置一個「長」,除了其大小的倍數的地址。 – 2010-08-01 13:29:53

回答

3

我看看在每個這些技術所產生的組件中,使用下面的程序:

#include <new> 

char blob[128]; 

int main() { 
    void *pLocation = blob; 
    char pattern = 'x'; 
#ifdef CAST 
    *reinterpret_cast<char*>(pLocation) = pattern; 
#else 
    ::new(pLocation) char(pattern); 
#endif 
} 

我使用克++ 4.4.3 Linux上的64位與默認編譯器標誌。

的ASM爲放置新相關部分:

movb $120, -1(%rbp) 
    movq -16(%rbp), %rax 
    movq %rax, %rsi 
    movl $1, %edi 
    call _ZnwmPv 
    movq %rax, %rdx 
    testq %rdx, %rdx 
    je .L5 
    movzbl -1(%rbp), %edx 
    movb %dl, (%rax) 
.L5: 

從我所收集,這實際上是調用放置新的運營商,並檢查它的返回值,即使它總是成功的。然後繼續將x的值寫入返回的內存中。

而對於reinterpret_cast

movb $120, -1(%rbp) 
    movq -16(%rbp), %rax 
    movzbl -1(%rbp), %edx 
    movb %dl, (%rax) 

注意,這些說明是相同的前兩個和最後兩個位置new版本。

使用-O1,代碼兩片產生相同組件:

movb $120, blob(%rip) 

所以,如果你擔心性能,不要。任何其他理智的編譯器都可能會同時減少相同的代碼。

3

雖然鑄造原始內存到對象可能在實際工作中,正式它調用未定義的行爲,並作爲其結果,根據該C++標準,你的代碼可能會做任何事情。

安置新的OTOH是一種調用特定地址的構造函數的技術,而構造是正式將原始內存轉換爲有效對象的原因,這就是爲什麼我更願意放置新的。只是爲了確定,我也會有析構函數因爲這樣的對象被稱爲。雖然你說你只需要這個POD和POD的銷燬是沒有用的,但我在運營商看到的許多錯誤都是在代碼中寫入的,這些代碼是在考慮了一系列限制的情況下編寫的,但後來一些限制被解除突然發現自己處於一個無法應付的環境中。

另請注意,有些平臺可能並不是所有可能的位模式都是有效值,即使是內置類型也是如此。這樣的平臺也可能會陷入對這種模式價值的訪問。例如,可能全零位模式對於浮動類型不是有效值,所以即使將存儲器置零也不能防止硬件異常。