放置新的零是否会占用内存? [英] Does placement new zero out the memory?

查看:94
本文介绍了放置新的零是否会占用内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

struct foo {};
void bar(foo *d) {
  new(d) foo(*d);
}

表达式new(d) foo(*d)是否使d指向的对象保持不变?更具体地说,如果类foo及其包含在其中的所有对象仅具有琐碎的复制构造函数,那么new(d) foo(*d)保持*d不变,那么上述说法是否正确?在不正确的情况下,new首先将内存清零,然后再调用复制构造函数. C ++语言中有这样的子句吗?

Does the expression new(d) foo(*d) leave the object pointed to by d unchanged? More specifically, is the above true if the class foo and all the objects contained recursively within it only have trivial copy constructors, then does new(d) foo(*d) leave *d unchanged? A situation in which that is not true could be, new first zeroes out the memory before calling the copy constructor. Are there such clauses in the C++ language?

编辑:有人要这么做有很重要的原因.考虑跨地址空间复制对象,例如,从CPU内存复制到GPU内存.一种解决方案是逐个字节地处理对象.这在很多情况下都有效.如果该类具有虚拟方法,则逐字节副本将复制vtable指针,然后该vtable指针将指向某些CPU内存.可以在对象上使用上面的表达式new(d) foo(*d)来强制编译器重置vtable指针.

Edit : There are non-trivial reasons why someone would want to do this. Consider copying objects across address spaces, say, from CPU memory to GPU memory. One solution for that is to do a byte-by-byte of the object. This works in lot of cases. If the class has virtual methods, then the byte-by-byte copy copies the vtable pointer, which would then be pointing to some CPU memory. One can use the above expression new(d) foo(*d) on the object to force the compiler to reset the vtable pointer.

推荐答案

我在研究性能问题时碰到了这个问题.某些在包含大缓冲区的对象上使用new放置的代码出乎意料的缓慢.原因是:new放置是在调用构造函数之前将内存清零.

I have just come across this question while researching a performance problem. Some code that uses placement new on objects which contained large buffers was unexpectedly slow. The reason: placement new was zeroing out the memory before calling the constructor.

我对标准的阅读与其他答案一致:不需要编译器做任何特别的事情.

My reading of the standard is in agreement with the other answers: The compiler is not required to do anything in particular.

但是,在新情况下,gcc 4.9,gcc 5.3,clang 3.4,clang 3.8和Apple clang似乎都将内存清零了.检查汇编程序输出,在调用构造函数之前先显式调用memset.堆栈构造的对象不是零初始化的,因此似乎不是构造函数来完成工作.

However, gcc 4.9, gcc 5.3, clang 3.4, clang 3.8 and Apple clang all seem to zero out memory in the placement new case. Examining the assembler output, there is an explicit call to memset before calling the constructor. Stack constructed objects are not zero-initialised, so it doesn't seem to be constructor doing the work.

检查Dignus Systems/C ++ for z/OS的汇编程序输出似乎也调用了一个库函数,大概是在做类似的事情(而且很慢).

Examining assembler output from Dignus Systems/C++ for z/OS also seems to call a library function, presumably doing something similar (and slow).

所以:新的Placement允许将内存清零,并且似乎许多实现都将内存清零.

So: Placement new is allowed to zero out the memory and it seems that many implementations do zero out memory.

示例测试用例:

#include <new>
#include <cstdint>
#include <stdio.h>

struct Test {
    char b[4];

    void show(char const* prefix) {
        for (unsigned i = 0; i < sizeof(b); ++i)
            printf("%s index %d: %d\n", prefix, i, b[i]);
    }
};

int main()
{
    char* p = new char[sizeof(Test)];

    for (unsigned i = 0; i < sizeof(Test); ++i)
        p[i] = 'Q';

    Test* t1 = new(p) Test();
    Test t2;

    t1->show("t1");
    t2.show("t2");
}

示例输出(在FreeBSD上为clang 3.4):

Example output (clang 3.4 on FreeBSD):

t1 index 0: 0
t1 index 1: 0
t1 index 2: 0
t1 index 3: 0
t2 index 0: 51
t2 index 1: -1
t2 index 2: 3
t2 index 3: 1

这篇关于放置新的零是否会占用内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆