Although the current answers are basically correct, this is undefined behavior because you are using an indeterminate value the details are a bit more involved. For primitive types I believe either Does initialization entail lvalue-to-rvalue conversion? Is int x = x; UB? or Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++1y? provide sufficient detail to understand why the behavior is undefined.
For a user defined type though I don't think they fill in enough of the details. We can see from this rather old but relevant defect report 63: Initialization of class from self which asks:
And if so, what is the semantics of the self-initialization of UDT?
and provides an example in which only the reference and the address is taken of the class under construction and the answer says:
3.8 basic.life paragraph 6 indicates that the references here are valid. It's permitted to take the address of a class object before it
is fully initialized, and it's permitted to pass it as an argument to
a reference parameter as long as the reference can bind directly.
It is referring to section 3.8
Object lifetime because the object is under construction and its storage has been allocated but it lifetime has not began because its initialization is not complete.
If we look at paragraph 6
from section 3.8
it says (emphasis mine):
Similarly, before the lifetime of an object has started but after the
storage which the object will occupy has been allocated or, after the
lifetime of an object has ended and before the storage which the
object occupied is reused or released, any glvalue that refers to the
original object may be used but only in limited ways. For an object
under construction or destruction, see 12.7. Otherwise, such a glvalue
refers to allocated storage (3.7.4.2), and using the properties of the
glvalue that do not depend on its value is well-defined. The program
has undefined behavior if:
and includes:
the glvalue is used to access a non-static data member or call a
non-static member function of the object,
So before the initialization is complete we can not take the value of a non-static data member which clearly will be required during copy construction of a std::string
.