If memory is allocated with malloc
(as opposed to new
) and an object is moved into that memory, is that valid C++?
Let's say I allocate memory for an array of n objects of type T
, and I have a range of n objects of type T
that I want to move into that, is this valid:
T* next = (T *)malloc(n*sizeof(T));
T* t = std::begin(my_range);
while (we still have more Ts) {
*next = std::move(*t);
++next;
++t;
}
This seems to work, but I'm curious as to why it would since we never new the objects in the allocated memory that we move to.
My guess is placement new is the correct way to do it:
while (we still have more Ts) {
new (next) T(*t);
++next;
++t;
}
but I'd like to know WHY the first one is incorrect, and if so, if it just works by luck or because T
happens to be a POD.
malloc() does not initialize the memory allocated, while calloc() guarantees that all bytes of the allocated memory block have been initialized to 0.
defines a named array object. Your pointer declaration and initialization does not. However, the malloc call (if it succeeds and returns a non- NULL result, and if n > 0 ) will create an anonymous array object at run time. But it does not "define an array a ".
malloc(): It is a C library function that can also be used in C++, while the “new” operator is specific for C++ only. Both malloc() and new are used to allocate the memory dynamically in heap. But “new” does call the constructor of a class whereas “malloc()” does not.
In C, dynamic memory is allocated from the heap using some standard library functions. The two key dynamic memory functions are malloc() and free(). The malloc() function takes a single parameter, which is the size of the requested memory area in bytes. It returns a pointer to the allocated memory.
If memory is allocated with malloc (as opposed to new) and an object is moved into that memory, is that valid C++?
Potentially; Not necessarily.
If we consider move-construction then sure, you can use placement-new to create an object into the memory. A bit like in your second example - except the example does a copy; unless the iterator is strange and returns an rvalue. Although, you mention the type being a POD in which case there is no difference between a move and a copy.
If we consider move assignment, then it is well defined only if there has previously been created an object into that memory. In your first example, no objects have been created, so the behaviour is technically undefined.
I'd like to know [...] if it just works by luck or because T happens to be a POD.
Technically UB, but is very likely to work if T
is POD. This type of initialisation by assignment is well defined in C (and the only way to create objects dynamically in that language).
If the assignment operator were non-trivial, then stuff would very likely break.
To move a range of objects into uninitialised memory, you'd probably want to use std::uninitialized_move
. It'll be well defined regardless of triviality of the type, and you don't even have to write a loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With