In C++, is this code correct?
#include <cstdlib>
#include <cstring>
struct T // trivially copyable type
{
int x, y;
};
int main()
{
void *buf = std::malloc( sizeof(T) );
if ( !buf ) return 0;
T a{};
std::memcpy(buf, &a, sizeof a);
T *b = static_cast<T *>(buf);
b->x = b->y;
free(buf);
}
In other words, is *b
an object whose lifetime has begun? (If so, when did it begin exactly?)
From a quick search.
So, I would say by this definition, the lifetime begins with the allocation and ends with the free.
This is unspecified which is supported by N3751: Object Lifetime, Low-level Programming, and memcpy which says amongst other things:
I can not find any meeting minutes that has this paper discussed, so it seems like it is still an open issue.
The C++14 draft standard currently says in
1.8
[intro.object]:which we don't have with the
malloc
and the cases covered in the standard for copying trivial copyable types seem to only refer to already existing objects in section3.9
[basic.types]:and:
which is basically what the proposal says, so that should not be surprising.
dyp points out a fascinating discussion on this topic from the ub mailing list: [ub] Type punning to avoid copying.
Propoal p0593: Implicit creation of objects for low-level object manipulation
The proposal p0593 attempts to solve this issues but AFAIK has not been reviewed yet.
It has some motivating examples which are similar in nature including a current std::vector implementation which currently has undefined behavior.
It proposes the following ways to implicitly create an object:
Well, it will usually "work", but only for trivial types.
I know you did not ask for it, but lets use an example with a non-trivial type:
After constructing
a
,a.x
is assigned a value. Let's assume thatstd::string
is not optimized to use a local buffer for small string values, just a data pointer to an external memory block. Thememcpy()
copies the internal data ofa
as-is intobuf
. Nowa.x
andb->x
refer to the same memory address for thestring
data. Whenb->x
is assigned a new value, that memory block is freed, buta.x
still refers to it. Whena
then goes out of scope at the end ofmain()
, it tries to free the same memory block again. Undefined behavior occurs.If you want to be "correct", the right way to construct an object into an existing memory block is to use the placement-new operator instead, eg: