2010-08-01 76 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的销毁是没有用的,但我在运营商看到的许多错误都是在代码中写入的,这些代码是在考虑了一系列限制的情况下编写的,但后来一些限制被解除突然发现自己处于一个无法应付的环境中。

另请注意,有些平台可能并不是所有可能的位模式都是有效值,即使是内置类型也是如此。这样的平台也可能会陷入对这种模式价值的访问。例如,可能全零位模式对于浮动类型不是有效值,所以即使将存储器置零也不能防止硬件异常。