UB is not a language specific "thing". It is "what you are doing doesn't have a defined behaviour". So the reason that "using uninitialized memory is undefined" is that the language C can not stipulate what should happen if you read memory that hasn't been written to. As discussed in another answer, if the memory is not initialized, it may have parity or ECC errors, because the parity bit is set correctly on the first write. When memory contains "whatever it came out of power-up as", it may well have the wrong parity/ecc value.
ECC or parity errors often lead to the system stopping, because it's not expected to have bad memory!
So, it's not what language the code you execute is written in that matters, it is "the behaviour if you read from memory that hasn't been initialized could go wrong". The act of reading the memory, whether the code is written in C, C++, assembler, Pascal, Fortran or LisP.
And bear in mind that undefined isn't necessarily that "Bad things happen", just that "the specification does not explain what the result is, and bad things are allowed to happen in UB". Dividing by zero is not guaranteed to crash your program - it most likely will, but it may also just give you back the same value as you fed in on the other side of the
/ - that would be perfectly valid UB. Reading uninitialized memory can result in "you get zero", or "you get all ones", or "you get some mixture of ones and zeros, nobody knows which ones", or "could lead to the system rebooting due to suspected memory error". And of course, it may not be the same every time either - sometimes the parity bits are "right", sometimes not, for example.
To clarify: I'm not one of those people that know every paragraph of every section of the C or C++ standards. I write code for a living, and I know enough of how processors and connected hardware to understand WHY the specifications say "it is undefined behaviour when you ..." [it probably doesn't use those words at all, since standards don't use second person] - in the case of using variables that haven't been initialized, the C language doesn't try to enforce any particular behaviour, because it MAY restrict the language from being used on a particular platform, because the platform can't guarantee that behaviour [and if you specify a behaviour, someone will rely on that behaviour sooner or later, making it a necessary part to implement on every platform].