Does placement new zero out the memory?

拥有回忆 提交于 2019-12-23 22:15:11

问题


I have the following code :

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

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?

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.


回答1:


On whether placement new zeroes out the memory, it does not, it just calls the appropriate constructor that will do whatever that constructor does, which could zero out the memory or not depending on how it is defined. In this particular case you are using the copy constructor

As of the code that you present, it is undefined behavior. Either d points to a valid object or it does not. If it refers to a valid object you are calling a constructor on an already constructed object, which is undefined behavior if the object has a non-trivial destructor. If it has not been initialized before (i.e. it does not refer to a foo object), then it is undefined behavior to copy from it.




回答2:


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.

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.

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

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

Example test case:

#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");
}

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



回答3:


I believe this is undefined behaviour: The lifetime of an object ends once the memory in which it is stored is used for something else. The moment you enter the copy constructor with the this pointer being equal to d, the original object ceases to exist (as far as the language is concerned), and so you have a dangling reference in the copy constructor.

Even easier of course is the situation where ~foo() has effects, in which case you have yet another reason for undefined behaviour.




回答4:


Note that you are calling the copy constructor of an object with itself as the copy-from. I would expect this to go simply nuts. Who knows. I don't see anything in the standard that would lead me to expect anything.




回答5:


Placement new's only job is to run the constructor on memory that has been set aside for an object that has not yet been initialized. It does nothing more and nothing less than what you would get if you manually called the constructor (though that is not possible) instead.



来源:https://stackoverflow.com/questions/10490191/does-placement-new-zero-out-the-memory

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!