Consider following sample code:
class C
{
public:
int* x;
};
void f()
{
C* c = static_cast(malloc(sizeof(C)));
c->x = nullptr; // &
I think it shouldn't be UB. You make your pointer point to some raw memory and are treating its data in a particular way, there's nothing bad here.
If the constructor of this class does something (initializes variables, etc), you'll end up with, again, a pointer to raw, uninitialized object, using which without knowing what the (default) constructor was supposed to be doing (and repeating its behavior) will be UB.