Examples suffer from being oversimplified. For example, the components you list are (in real life) not only attached to the car, but also to the adjacent components themselves. In programming terms, Engine would have a direct reference to Transmission, and so on.
A better analogy here would be a desktop PC. All components are plugged into the motherboard. You don't connect your CPU to your graphics card or your HDD directly, they all get connected to the same motherboard which does the routing between components. This reflects your code example, as Car acts as the mediator between all of its components.
It causes Car to (indirectly) contain a bunch of pointers to itself
You're ignoring the basic encapsulation principle here, because the internal component logic is not something that Car cares about, and therefore the consideration you mention is not relevant. Car does not contain references to itself. It contains components. Those components just happen to have a symmetric reference to the car they belong to.
forcing me to declare copy and move constructors manually, creating unnecessary space for bugs
I'm no C++ dev so I'll take your statement at state value, but if it is necessary that the component needs a reference to their car, and doing so inherently means declaring copy and move constructors, then this implementation is not "unnecessary" as you call it.
Also as a minor issue this needlessly inflates the size of Car class.
I'm not saying that memory footprint doesn't matter, but you're inverting the order of operations here. The feature requirement is more important than the space optimization, so if this is what you need, then you're not wasting the extra space it requires.
In a magical perfect-c++-land I'd be able to create some sort of a namespace inside the Car class, adding a eg. Engine:: prefix to all names belonging to engine, but keeping the this pointer pointing to the top level Car object.
This violates the basic premise of encapsulation. You're effectively breaking down the borders between your individual classes just to avoid storing a pointer. This is the equivalent of not putting a front door in your house because the people you live with would rather not put a key in their pockets. The end really does not justify the means here.
What do you use in cases like this?
I prefer symmetrical references like you already used. Pointers take more effort in C++ than they do in e.g. C#, but that's the nature of the beast. C++ is not the easiest language to work with. With great control comes the need for significant amounts of handholding and pedantry.
The principle of OOP does not change just because your programming language changes, even if C++ is more complex than other languages.
Are there some alternative workarounds?
You don't need the symmetric relationship if the communication only works one way.
Rather than "engine needing to send its rpm to transmission", think of it like "car asks engine for its RPM, and car then gives the RPM value to transmission".
Now, only car needs a reference to its components, not the other way around, and thus you don't need to pass the car reference to the components. Whether that works for your use case very much depends on your specific use case.