views:

192

answers:

3

How does the following code work in C++? Is it logical?

const int &ref = 9;
const int &another_ref = ref + 6;

Why does C++ allow literal initialization for const references when the same is not permitted for non-const references? E.g.:

const int days_of_week = 7;
int &dof = days_of_week; //error: non const reference to a const object

This can be explained by the fact that, a non-const reference can be used to change the value of the variable it is referring to. Hence, C++ does not permit a non-const reference to a const variable.

Could this be a possible explanation? C++ does not allow:

int &ref = 7;

Because that is not logical, but:

const int &ref = 7;

Is almost equivalent to:

const int val = 7;

So literal initialization is permitted for const variables.

P.S.: I'm currently studying Lippman's C++ Primer.

+6  A: 

So you can write code like this:

void f( const string & s ) {
}

f( "foobar" );

Although strictly speaking what is actually happening here is not the literal being bound to a const reference - instead a temprary string object is created:

string( "foobar" );

and this nameless string is bound to the reference.

Note that it is actually quite unusual to create non-parameter reference variables as you are doing - the main purpose of references is to serve as function parameters and return values.

anon
+3  A: 

Constant references can be initialized with literals and temporaries because you can trivially transform them to explicit variables:

int const& ans = 42;
// tranformed:
int __internal_unique_name = 42;
int const& ans = __internal_unique_name;

Or when the lifetime is not extended, such as a function parameter:

f("foobar");
// transformed:
{
  string __internal_unique_name = "foobar";
  f(__internal_unique_name);
}

(Notice the explicit block in this case.)

While it's possible to do something similar in the non-constant case, that's just not allowed in currenct C++. C++0x (the next standard), however, will have r-value references.


If it wasn't clear, ref + 6 from your code creates a temporary object, which you can visualize as:

int const& ref = int(9);
int const& another_ref = int(ref + 6);

// transformed:
int __A = 9;
int const& ref = __A;
int __B = ref + 6;
int const& another_ref = __B;

This may help you understand/visualize what is happening, but you should not write real code like this. Also I've used double underscore names to illustrate those names are implementation details (used by the compiler) and should not be used by you. Any name which contains adjacent underscores is reserved to the C++ implementation.

Roger Pate
+1. But I think your second example would be transformed to { string __internal_unique_name("foobar"); f(__internal_unique_name);}
rstevens
@rstevens: it doesn't matter: the conversion must not be explicit, in which case they are the same.
Roger Pate
+2  A: 

Your code boils down to the C++ standard rule where the lifetime of a temporary value is bound to the lifetime of the const reference to which it is assigned. See the GoTW article GotW #88: A Candidate For the “Most Important const” for additional details.

For example, the ScopeGuard implementation, described by Alexandrescu and Marginean in the Dr. Dobbs article "Generic: Change the Way You Write Exception-Safe Code — Forever" depends on this behavior.

Void