I think there is a misconception on your part. Formally, there is no "half-constructed" object, at least not in any way that's missing an automatic mechanism to unwind mid-way (i.e. half-deconstruct).
Each object construction is a list of N + 1 construction stages -- constructing the N subobjects (implicitly or as per the initializer list), followed by the constructor body.
The destructor has N + 1 stages too, those match exactly the constructor's stages. If there is an exception happening in any stage of the constructor, say stage E, naturally only stages 0 to E-1 get un-done (in reverse), but not E nor any later stage.
So what you have to do is imagine that all sub-objects are already constructed, and imagine there is a function that runs the constructor body and destructor body in a sequence. The constructor part could throw an exception, causing the destructor part to never run. Like any other function, it should be possible to run it without leaking anything if an exception happens. Make it "exception safe" using RAII or by being extra careful.
If you've written constructor and destructor such that they match in this way (which is, again, like you would write any other function), then will work correctly in all cases. This is a powerful concept and pretty much fool-proof. I say that as someone who has lots of concerns about the language's complexity -- including exceptions.