Greetings, everyone!
Examining my own code, I came up to this interesting line:
const CString &refStr = ( CheckCondition() ) ? _T(\"foo\") : _T(\"bar
An exception will bring you to a place where refStr isn't accessible and you can't go to a place where it is from there. A goto won't be able to get out of CheckCondition() if it is a function, and you won't be able to use a goto if it is a macro. A longjmp() will have the same effect as an exception: you'll go to a place where refStr isn't accessible.
This is completely legal. Either this finishes successfully and the reference is bound to a valid object or an exception is thrown and control is transferred outside the block and the reference is no longer in scope so noone cares of it anymore.
You are missing something - it is completely legal code, and in fact such code is one of the commonest and best uses of the conditional operator. It's always a mistake to think that the compiler must internally do things in the same order that the code is layed out on the page - it is perfectly at liberty to evaluate the conditional operator (which is justv another expression) and then use the result to perform the initialisation.
As for a goto, there is no way of using one in an initialisation. And if an exception is thrown, the reference is deemed never to have been created in the first place.
Simpler example: const int x = foo();
This constant too has to be initialized, and for that foo()
needs to be called. That happens in the order necessary: x comes into existance only when foo returns.
To answer your additional questions: If foo()
would throw
, the exception will be caught by a catch()
somewhere. The try{}
block for that catch()
surrounded const int x = foo();
obviously. Hence const int x
is out of scope already, and it is irrelevant that it never got a value. And if there's no catch
for the exception, your program (including const int x
) is gone.
C++ doesn't have random goto
's. They can jump within foo()
but that doesn't matter; foo()
still has to return.
I can see now, that while CheckCondition() is executed, refStr exists, but still not initialized.
From a language lawyer point of view, this is wrong. During initialization, refStr
doesn't exist yet. I'd guess that your visual debugger is giving you misleading hints.
If the code inside the initialization leads to an error condition, refStr
will not exist, and will not ever have existed.
Uninitialized references cannot exist.
Unfortunately funny things can be done during initialization. You could have also written
const int& a = foobar(a) ? 1 : 2;
or for the matter
const int& a = a;
I suppose as the compiler proceeds from left to right, a is indeed in scope on the right side, so technically you should be able to use it and at best it can warn:
"ComeauTest.c", line 9: warning: variable "a" is used before its value is set
const int& a = foobar(a) ? 1 : 2;
^
Naturally this can only result in undefined behavior as with using any uninitialized variable.
Your example is fine, since you don't use the reference before it has been initialized.