Question

Greetings, everyone!

Examining my own code, I came up to this interesting line:

const CString &refStr = ( CheckCondition() ) ? _T("foo") : _T("bar");

Now I am completely at a loss, and cannot understand why it is legal. As far as I understand, const reference must be initialized, either with r-value or l-value. Uninitialized references cannot exist. But ()? operator executes a CheckCondition() function before it assigns value to the reference. I can see now, that while CheckCondition() is executed, refStr exists, but still not initialized. What will happen if CheckCondition() will throw an exception, or pass control with a goto statement? Will it leave the reference uninitialized or am I missing something?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

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.

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top