So a bit of C++ code:
void func( const std::string& theString )
{
std::string theString( theString );
theString += " more string";
std::cout << theString;
}
which compiles fine with GCC 4.8
and VS 2013
. From my C++ knowledge, the code is okay with a local variable theString
being brought into scope which then hides theString
from the function argument. At the point of theString
construction, the only theString
in scope is the function argument which is passed to the std::string
constructor. The constructed std::string
is then named theString
which comes into scope and is theString
used later in the code. Phew!
However, GCC
seems to act like theString
passed to the std::string
constructor is the local theString
(which hasn't been constructed yet) causing the compiled program to crash. With VS 2013 the code compiles and runs fine.
So,
No, your code is invalid.
According to the C++ Standard (3.3.2 Point of declaration)
1 The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below.
[ Example:
int x = 12;
{ int x = x; }
Here the second x is initialized with its own (indeterminate) value. —end example ]
And (3.3.3 Block scope, #2)
A parameter name shall not be redeclared in the outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block.
This is undefined behaviour in C++. paxdiablo quotes the C++03 standard:
The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any) ...
Example:
int x = 12; { int x = x; }
Here the second x is initialized with its own (indeterminate) value.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With