malloc a struct is UB in C++?

Hi everyone,

I stumbled upon a CppCon talk
https://youtu.be/_qzMpk-22cc?t=1277
From 21:15 to 25:00, the speaker claims that the following code is fine in C but undefined behavior in C++:

struct X
{
int a;
int b;
};
X* get_X()
{
X* p = (X*)malloc(sizeof(struct X));
p->a = 1;
p->b = 2;
return p;
}

He talked about some rules in C++ Standard that claim that this is UB.
Shouldn't the C be the subset of C++?
And what is the speaker talking about?

I am asking this because there is similar code in handmade hero codebase.

Thanks.

Edited by spaskeasm on
He was wrong.

Trivial types (that is types with no constructor or destructor and every non-static member field is also of a trivial type) start their lifetimes as soon as they are allocated.

I am just reading the standard https://github.com/cplusplus/draft/raw/master/papers/n4830.pdf
6.6.3.7 about objects and lifetimes.

It doesn't mention anything about trivial types.

I wasn't speaking spec-ese. In the spec you'll see vacuous initialization. It's under that umbrella that this is valid.

Or at least every compiler treats it as valid.
spaskeasm

Shouldn't the C be the subset of C++?


No. C is not subset of C++. There are multiple features where C code behaves differently when compiled as C++.

Most simple case is sizeof('a'). In C it is 4 (on x86 or similar). In C++ it is 1.
According to the C++ > 11 standard X is a POD type. POD means "Plain Old Data", and it's a thing well defined in the standard. I don't think this is UB at all, and if it is UB, then I know of don't know any compiler that would treat this as UB.

TLDR; C++ is a broken mess.

Edited by Matyas on
After reading the standard some more, it doesn't say anything about malloc.

It says that if the constructor is not called, there is no object there and therefor is UB to access that object through pointer or reference.

To be C++ complaint it would have to look like something like this:

x* AllocateXFromStorage(storage* Storage);

void Foo()
{
x* X= AllocateXFromStorage(Storage);
new (X) x; // <- add this bullshit
// .. use it here
}

If AllocateXFromStorage returns properly aligned address and new (X) x is called even if it doesn't do anything on POD,
and will get optimized out by the compiler than this is C++ Standard complaint and not a UB.

Without new(X) x; it is but every compiler that I have checked (gcc, clang, msvc) will do what it is expected.

There is even a proposal to fix this for sufficiently trivial types.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0593r4.html