To be fair, the c++ programmer can also use reference semantics via pointers. Granted, garbage collection is not built into the language, but if desired, we can always write java-style code by using pointers for everything and using the Boehm collector. I don't know why we don't do this more often, most c++ codebases seem to have large sections that would benefit from such a style.
But when we want to use value semantics, for whatever reason, the more complicated value copy is, to some extent, just intrinsically complicated. In java, Object.clone basically has all of the same problems -- you sort of know what you'd like it to do for any given object in any given context, but you've got to read code to figure out what is actually going to happen.
> I don't know why we don't do this more often, most c++ codebases seem to have large sections that would benefit from such a style.
Because you will sacrifice performance over Java's GC. For maximum performance you really want precise garbage collection on both stack and heap, with generational concurrent operation and a two space copying collector in the nursery. Boehm can't provide this, because the language is not designed for GC.
I don't mean a garbage collected stack per se (though since you asked, SML/NJ has this, as do several Schemes). What I mean is that precise stack maps or register tagging is used so that the roots can precisely be found on the stack.
But when we want to use value semantics, for whatever reason, the more complicated value copy is, to some extent, just intrinsically complicated. In java, Object.clone basically has all of the same problems -- you sort of know what you'd like it to do for any given object in any given context, but you've got to read code to figure out what is actually going to happen.