non-const reference and const reference

This is my understanding of non-const reference, const reference and
their relationships with lvalue/rvalue. Please help to review whether
it is correct and feel free to correct me. Thanks.

1. A const reference can be binded to a rvalue, for example, a
temporary object. And the "life" of the temporary object is guaranteed
to be extended and we can safely operate through the const-reference.

2. A non-const reference can not binded to a rvalue, I think the
reason is rvalue is not addressable? And we can not change the rvalue
through its reference? Are there any other reasons? I am not quite
sure whether my understanding is fully correct. Since there are some
non-modifiable lvalues (so we do not always need to modify values
through its reference). I am still studying what is the reason in
essence in compiler why a non-const reference can not be binded to a
rvalue.

Advertisements

* George2:
> Hello everyone,
>
>
> This is my understanding of non-const reference, const reference and
> their relationships with lvalue/rvalue. Please help to review whether
> it is correct and feel free to correct me. Thanks.
>
> 1. A const reference can be binded to a rvalue, for example, a
> temporary object. And the "life" of the temporary object is guaranteed
> to be extended and we can safely operate through the const-reference.

Not quite.

Lifetime extension of temporary happens when the reference is declared
in local scope.

It does not happen when you return a reference from a function.

> 2. A non-const reference can not binded to a rvalue, I think the
> reason is rvalue is not addressable?

No, an rvalue can have an address. In particular, you can call member
function on class type rvalues, and you can bind the rvalue to a
reference to const. But note that "rvalue" refers to syntax, how you
denote an object: it's not a property of the object so denoted.

> And we can not change the rvalue
> through its reference? Are there any other reasons?

Consider

void increment( unsigned& x ) { ++x; }

int main() { int y = 0; increment( unsigned(y) ); }

The cast produces an rvalue. If this compiled it would presumably
increment a temporary instead of y.

Bottom line is by disallowing that binding one avoids many pitfalls.

> I am not quite
> sure whether my understanding is fully correct. Since there are some
> non-modifiable lvalues (so we do not always need to modify values
> through its reference). I am still studying what is the reason in
> essence in compiler why a non-const reference can not be binded to a
> rvalue.
>
> 3. Both const and non-const reference can be binded to a lvalue.

Yes.

Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Advertisements

On Dec 15, 6:33 am, "Alf P. Steinbach" <> wrote:
> * George2:
> > This is my understanding of non-const reference, const reference and
> > their relationships with lvalue/rvalue. Please help to review whether
> > it is correct and feel free to correct me. Thanks.
> > 1. A const reference can be binded to a rvalue, for example, a
> > temporary object. And the "life" of the temporary object is guaranteed
> > to be extended and we can safely operate through the const-reference.
> Not quite.
> Lifetime extension of temporary happens when the reference is
> declared in local scope.

Not at all. There are exactly three cases where the temporary
has a different lifetime than the reference: when the reference
is a class member (in that case, lifetime of the temporary is
extended to match the lifetime of the entire constructor, but of
course, the reference itself has the same lifetime as the
constructed object); when the reference is a function argument
(in which case, the temporary naturally has a longer lifetime
than the reference to begin with), and when the reference is a
return value (the temporary only persists until the function
exits).

On the other hand, there's certainly no restriction to local
scope; the lifetime is extended in all other cases.

The usual problem that people have is that the lifetime isn't
extended when a temporary is bound to a reference; the compiler
can't even know, in the general case, if what it is binding is a
temporary. The lifetime is extended when the reference is
*initialized* with a temporary. The difference is a bit subtle;
what it comes down to is that the lifetime is extended *only*
when the initialization expression is a temporary; not when it
is another reference (which might be bound to a temporary). The
best way to think of it in practice, I find, is to consider that
the extension of the lifetime isn't transitive.
> It does not happen when you return a reference from a function.

Nor when you initialize a member. On the other hand, it applies
to global references just as much as to local ones.

Not "If this compiled", but "When it was legal C++ and
compiled". The earliest versions of C++ (up to about 1988, I
think) allowed this, with exactly the semantics you suggest.
The restriction was introduced exactly because the rule was so
error prone.

* James Kanze:
> On Dec 15, 6:33 am, "Alf P. Steinbach" <> wrote:
>> * George2:
>
>>> This is my understanding of non-const reference, const reference and
>>> their relationships with lvalue/rvalue. Please help to review whether
>>> it is correct and feel free to correct me. Thanks.
>
>>> 1. A const reference can be binded to a rvalue, for example, a
>>> temporary object. And the "life" of the temporary object is guaranteed
>>> to be extended and we can safely operate through the const-reference.
>
>> Not quite.
>
>> Lifetime extension of temporary happens when the reference is
>> declared in local scope.
>
> Not at all. There are exactly three cases where the temporary
> has a different lifetime than the reference: when the reference
> is a class member (in that case, lifetime of the temporary is
> extended to match the lifetime of the entire constructor, but of
> course, the reference itself has the same lifetime as the
> constructed object); when the reference is a function argument
> (in which case, the temporary naturally has a longer lifetime
> than the reference to begin with), and when the reference is a
> return value (the temporary only persists until the function
> exits).

I hear you say "not at all", then failing to give any counter-example.

> On the other hand, there's certainly no restriction to local
> scope

That's true.

>; the lifetime is extended in all other cases.

Sorry, that's false. You pointed out three cases above, yourself.

[snip]
>
>> It does not happen when you return a reference from a function.
>
> Nor when you initialize a member. On the other hand, it applies
> to global references just as much as to local ones.

[...]
> >>> 1. A const reference can be binded to a rvalue, for
> >>> example, a temporary object. And the "life" of the
> >>> temporary object is guaranteed to be extended and we can
> >>> safely operate through the const-reference.
> >> Not quite.
> >> Lifetime extension of temporary happens when the reference
> >> is declared in local scope.
> > Not at all. There are exactly three cases where the
> > temporary has a different lifetime than the reference: when
> > the reference is a class member (in that case, lifetime of
> > the temporary is extended to match the lifetime of the
> > entire constructor, but of course, the reference itself has
> > the same lifetime as the constructed object); when the
> > reference is a function argument (in which case, the
> > temporary naturally has a longer lifetime than the reference
> > to begin with), and when the reference is a return value
> > (the temporary only persists until the function exits).
> I hear you say "not at all", then failing to give any
> counter-example.

In the context above, your statement "declared in local scope"
implies, not elsewhere. That may not be what you meant, but it
sure sounded like it.
> > On the other hand, there's certainly no restriction to local
> > scope
> That's true.
> >; the lifetime is extended in all other cases.
> Sorry, that's false. You pointed out three cases above, yourself.

Exactly. All other cases than the ones I mentionned.
> [snip]
> >> It does not happen when you return a reference from a function.
> > Nor when you initialize a member. On the other hand, it applies
> > to global references just as much as to local ones.
> That's true.
>
> > [...]
> >> Consider
> >> void increment( unsigned& x ) { ++x; }
> >> int main() { int y = 0; increment( unsigned(y) ); }
> >> The cast produces an rvalue. If this compiled it would presumably
> >> increment a temporary instead of y.
> > Not "If this compiled", but "When it was legal C++ and
> > compiled".
> Sorry, that's bull. It makes no sense to talk about "valid"
> (or "legal") C++ before standardization.

You're either being intentionally obtuse, or just playing
stupid. So what was the language in which I wrote valid and
legal programs between 1991 (when I first started working
intensively in C++) and 1998 (when the standard was adopted).

The standardization committee didn't invent the word
C++.

In this case, it's worth pointing out that the original language
did allow initializing a non-const reference with a temporary.
The rule was changed as a result of concrete experience.
> > The earliest versions of C++ (up to about 1988, I think)
> > allowed this, with exactly the semantics you suggest. The
> > restriction was introduced exactly because the rule was so
> > error prone.
> In this group we discuss the C++ language.

Which has existed since at least 1986 (the publication date of
The C++ Programming Language).
> But yes, it would probably have been even better if I'd
> expressed the rules in terms of initialization rather than two
> examples.

The key problem I've seen in practice is that people seem to
think that a temporary will last as long as any reference is
bound to it. I personally find that it becomes clearer if the
explination is couched in terms of what happens with the
temporary: if the temporary is used to initialize a reference,
it's lifetime is extended to that of that reference. The point
of view is what happens to the temporary, and not what the
reference was initialized with.

Alternatively, some people seem to understand it better if I
simply state that the extension of lifetime is not transitive;
the fact that reference B is bound to reference A is bound to a
temporary doesn't mean that reference B's lifetime affects the
lifetime of the temporary.

I have no real theories as to why one explination works better
for some people, and the other one for others. Except that
people are different.

* James Kanze:
> On Dec 15, 11:38 pm, "Alf P. Steinbach" <> wrote:
>> * James Kanze:
>>> On Dec 15, 6:33 am, "Alf P. Steinbach" <> wrote:
>
> [...]
>>>>> 1. A const reference can be binded to a rvalue, for
>>>>> example, a temporary object. And the "life" of the
>>>>> temporary object is guaranteed to be extended and we can
>>>>> safely operate through the const-reference.
>
>>>> Not quite.
>
>>>> Lifetime extension of temporary happens when the reference
>>>> is declared in local scope.
>
>>> Not at all. There are exactly three cases where the
>>> temporary has a different lifetime than the reference: when
>>> the reference is a class member (in that case, lifetime of
>>> the temporary is extended to match the lifetime of the
>>> entire constructor, but of course, the reference itself has
>>> the same lifetime as the constructed object); when the
>>> reference is a function argument (in which case, the
>>> temporary naturally has a longer lifetime than the reference
>>> to begin with), and when the reference is a return value
>>> (the temporary only persists until the function exits).
>
>> I hear you say "not at all", then failing to give any
>> counter-example.
>
> In the context above, your statement "declared in local scope"
> implies, not elsewhere. That may not be what you meant, but it
> sure sounded like it.
>
>>> On the other hand, there's certainly no restriction to local
>>> scope
>
>> That's true.
>
>>> ; the lifetime is extended in all other cases.
>
>> Sorry, that's false. You pointed out three cases above, yourself.
>
> Exactly. All other cases than the ones I mentionned.
>
>> [snip]
>
>>>> It does not happen when you return a reference from a function.
>
>>> Nor when you initialize a member. On the other hand, it applies
>>> to global references just as much as to local ones.
>
>> That's true.
>>
>>> [...]
>>>> Consider
>
>>>> void increment( unsigned& x ) { ++x; }
>
>>>> int main() { int y = 0; increment( unsigned(y) ); }
>
>>>> The cast produces an rvalue. If this compiled it would presumably
>>>> increment a temporary instead of y.
>
>>> Not "If this compiled", but "When it was legal C++ and
>>> compiled".
>
>> Sorry, that's bull. It makes no sense to talk about "valid"
>> (or "legal") C++ before standardization.
>
> You're either being intentionally obtuse, or just playing
> stupid.

Are you really sure you want to go that road, James?

First posting a meaningless looks-like-a-clarification, then calling
names when you're taken up on it?

> So what was the language in which I wrote valid and
> legal programs between 1991 (when I first started working
> intensively in C++) and 1998 (when the standard was adopted).

Assuming you used more than one compiler or one compiler with more than
one set of options, the languages you used were not standard C++, and
they were not one language:

they were a number of slightly different languages, conforming in
general to Bjarne Stroustup's "reference manual" for C++.

By (May) 1991 that reference manual had already made the change we're
discussing here.

Programs using the earlier bind-temporary-to-reference-to-non-const
could still compile and in that sense be valid (for a given compiler),
for the intention was to "fade out" use of that feature. So your C++
programs written between 1991 and 1998 could get away with being valid
for the compiler(s) used, but invalid wrt. the "reference manual", and
neither valid nor invalid wrt. to any standard, not yet existing.

Interestingly, while the ARM cites the same rationale as I did earlier
for disallowing the non-const ref binding to temporary, in one Usenet
discussion I had with Bjarne Stroustrup about this, he cited his sense
of elegance and unified rules for allowing temporary lifetime extension,
just one rule fit all (and in particular also fitting argument passing).

So I think there were a number of factors influencing the decision.

> The standardization committee didn't invent the word
> C++.
>
> In this case, it's worth pointing out that the original language
> did allow initializing a non-const reference with a temporary.
> The rule was changed as a result of concrete experience.

Yes, it is a good example.

>>> The earliest versions of C++ (up to about 1988, I think)
>>> allowed this, with exactly the semantics you suggest. The
>>> restriction was introduced exactly because the rule was so
>>> error prone.
>
>> In this group we discuss the C++ language.
>
> Which has existed since at least 1986 (the publication date of
> The C++ Programming Language).
>
>> But yes, it would probably have been even better if I'd
>> expressed the rules in terms of initialization rather than two
>> examples.
>
> The key problem I've seen in practice is that people seem to
> think that a temporary will last as long as any reference is
> bound to it. I personally find that it becomes clearer if the
> explination is couched in terms of what happens with the
> temporary: if the temporary is used to initialize a reference,
> it's lifetime is extended to that of that reference.

Sorry, that's not the case, as you have yourself pointed out earlier.

> The point
> of view is what happens to the temporary, and not what the
> reference was initialized with.
>
> Alternatively, some people seem to understand it better if I
> simply state that the extension of lifetime is not transitive;
> the fact that reference B is bound to reference A is bound to a
> temporary doesn't mean that reference B's lifetime affects the
> lifetime of the temporary.
>
> I have no real theories as to why one explination works better
> for some people, and the other one for others. Except that
> people are different.

I think concrete examples work best, as foundation for later
generalization, and/or as clarification of an initial general statement.

At least for this subject there aren't that many really different cases,
so I think examples work fine, but the general rules get hairy --
especially if we get into the rules about copy constructor availability,
current and future.

Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

On Dec 16, 2:49 am, "Alf P. Steinbach" <> wrote:
> * James Kanze:
> >> [snip]
> >>>> It does not happen when you return a reference from a function.
> >>> Nor when you initialize a member. On the other hand, it applies
> >>> to global references just as much as to local ones.
> >> That's true.
> >>> [...]
> >>>> Consider
> >>>> void increment( unsigned& x ) { ++x; }
> >>>> int main() { int y = 0; increment( unsigned(y) ); }
> >>>> The cast produces an rvalue. If this compiled it would presumably
> >>>> increment a temporary instead of y.
> >>> Not "If this compiled", but "When it was legal C++ and
> >>> compiled".
> >> Sorry, that's bull. It makes no sense to talk about "valid"
> >> (or "legal") C++ before standardization.
> > You're either being intentionally obtuse, or just playing
> > stupid.
> Are you really sure you want to go that road, James?
> First posting a meaningless looks-like-a-clarification, then calling
> names when you're taken up on it?

First, I don't think the clarification was meaningless, because
I've consistently encountered people who misunderstood the issue
when it was presented in that way. And second, the attack is
less ad hominim than a constatation concerning one particular
statement, or way of reasoning. You statement "It makes no
sense to talk about "valid" (or "legal") C++ before
standardization" is simply ridiculous, and I know you know
better. So I have to suppose that you're making it for some
sort of rhetorical reason: being intentionally obtuse, playing
stupid (since I know you're not), or trying to provoke some sort
of reaction I can't see.
> > So what was the language in which I wrote valid and
> > legal programs between 1991 (when I first started working
> > intensively in C++) and 1998 (when the standard was adopted).
> Assuming you used more than one compiler or one compiler with
> more than one set of options, the languages you used were not
> standard C++, and they were not one language:
> they were a number of slightly different languages, conforming in
> general to Bjarne Stroustup's "reference manual" for C++.

I was there, and the ARM was taken very much as a "standard".
And with the exception of g++ (which really was a different
language at the time), conformance was generally better than
conformance to the ISO standard today. (Note that the chapters
in the ARM on templates and exceptions were considered more or
less experimental, and were not treated as part of the de facto
standard.)
> By (May) 1991 that reference manual had already made the
> change we're discussing here.

Become a standard? Again, I was there, and there was no ISO
standard until 1998. And the text that would be the standard
didn't really stabilize until 1996-1997. Until well after the
1998, most users considered the ARM as the reference, not the
ISO standard, simply because most compilers implemented
something much closer to the ARM than to the ISO standard.
> Programs using the earlier
> bind-temporary-to-reference-to-non-const could still compile
> and in that sense be valid (for a given compiler), for the
> intention was to "fade out" use of that feature.

In 1991, yes. The rule was changed before the ARM, and by 1991,
the ARM was rapidly becoming the definition of what was legal
and valid C++. The rule wasn't present in earlier versions of
"The C++ Programming Language", however, which was the reference
before the ARM.
> So your C++ programs written between 1991 and 1998 could get
> away with being valid for the compiler(s) used, but invalid
> wrt. the "reference manual", and neither valid nor invalid
> wrt. to any standard, not yet existing.

A program which bound a temporary to a non-const reference
wasn't valid or legal in 1991. And all of the "up to date"
compilers at the time warned (except maybe g++: at the time, g++
was so bad you couldn't use it). But I'm not sure what your
point is. There was a standard. I evolved over time, some
compilers took more time than others to update, and most treated
the new restrictions as warnings, rather than errors, to avoid
breaking existing code. The situation hasn't really changed,
except that instead of Stroustrup himself promulgating the
standard, it is defined by ISO.

The definition of what is "valid" and "legal" C++ evolves over
time.

Look. I posted because, from experience, I know that the
overall issue needs more clarification than you gave. Everytime
someone hears that "if a temporary is bound to a reference, it's
lifetime is extended to that of the reference", they seem to
assume transitivity (which, strictly speaking, is implied in the
statement, even if it wouldn't occur to me to assume it).

At the end of the statement, I made a minor, unimportant
correction, more in fun than anything else. (Maybe I should
have put a smiley on it.) Technically, it's not "if it
compiles" (since it doesn't), but "when it compiled" (since it
once did). And you come back with this bullshit that there was
no C++ language before ISO. Which, quite frankly, sort of
surprises someone like me who was using it back then; who was
writing C++ code, and sending in error reports to the compiler
vendors for non-conformance with the language specification:
"legal" and "valid" C++ code which didn't compile, or compiled,
but did the wrong thing, and C++ code which should not have
compiled, but did. Of course, we had to contend with the fact
that not all compilers implemented all of the latest
specification (but that's the case today as well), and that some
compilers intentionally deviated in certain cases (also the case
today).
> Interestingly, while the ARM cites the same rationale as I did
> earlier for disallowing the non-const ref binding to
> temporary, in one Usenet discussion I had with Bjarne
> Stroustrup about this, he cited his sense of elegance and
> unified rules for allowing temporary lifetime extension, just
> one rule fit all (and in particular also fitting argument
> passing).
> So I think there were a number of factors influencing the decision.

As I said, the reason you cited was the reason I'd always heard.
The example you gave is, in fact, the usual example I've seen.
I'm quite convinced that it is the explination of why the change
was made. My critical comment above is limited to your
statement that you couldn't talk about "legal" and "valid" C++
before ISO intervened, when we not only could, but did.

* James Kanze:
> On Dec 16, 2:49 am, "Alf P. Steinbach" <> wrote:
>> * James Kanze:
>>>> [snip]
>
>>>>>> It does not happen when you return a reference from a function.
>
>>>>> Nor when you initialize a member. On the other hand, it applies
>>>>> to global references just as much as to local ones.
>
>>>> That's true.
>
>>>>> [...]
>>>>>> Consider
>
>>>>>> void increment( unsigned& x ) { ++x; }
>
>>>>>> int main() { int y = 0; increment( unsigned(y) ); }
>
>>>>>> The cast produces an rvalue. If this compiled it would presumably
>>>>>> increment a temporary instead of y.
>
>>>>> Not "If this compiled", but "When it was legal C++ and
>>>>> compiled".
>
>>>> Sorry, that's bull. It makes no sense to talk about "valid"
>>>> (or "legal") C++ before standardization.
>
>>> You're either being intentionally obtuse, or just playing
>>> stupid.
>
>> Are you really sure you want to go that road, James?
>
>> First posting a meaningless looks-like-a-clarification, then calling
>> names when you're taken up on it?
>
> First, I don't think the clarification was meaningless, because
> I've consistently encountered people who misunderstood the issue
> when it was presented in that way. And second, the attack is
> less ad hominim than a constatation concerning one particular
> statement, or way of reasoning. You statement "It makes no
> sense to talk about "valid" (or "legal") C++ before
> standardization" is simply ridiculous, and I know you know
> better. So I have to suppose that you're making it for some
> sort of rhetorical reason: being intentionally obtuse, playing
> stupid (since I know you're not), or trying to provoke some sort
> of reaction I can't see.

It really doesn't make sense. Different compilers implemented different
languages. E.g., Borland's Turbo C++ implemented virtual calls from
constructors as they work in Java today, and IIRC Microsoft's Visual C++
(mid-90's) didn't have the exception classes specified by the draft.

>>> So what was the language in which I wrote valid and
>>> legal programs between 1991 (when I first started working
>>> intensively in C++) and 1998 (when the standard was adopted).
>
>> Assuming you used more than one compiler or one compiler with
>> more than one set of options, the languages you used were not
>> standard C++, and they were not one language:
>
>> they were a number of slightly different languages, conforming in
>> general to Bjarne Stroustup's "reference manual" for C++.
>
> I was there, and the ARM was taken very much as a "standard".
> And with the exception of g++ (which really was a different
> language at the time), conformance was generally better than
> conformance to the ISO standard today. (Note that the chapters
> in the ARM on templates and exceptions were considered more or
> less experimental, and were not treated as part of the de facto
> standard.)

Well, there you have it: in order to come with anything resembling a
common well-defined language you have to resort to a subjective view of
which parts of the ARM -- or draft standard -- were significant.

>> By (May) 1991 that reference manual had already made the
>> change we're discussing here.
>
> Become a standard?

Tell me, are you reading someone else's articles and answering mine?

> Again, I was there, and there was no ISO
> standard until 1998. And the text that would be the standard
> didn't really stabilize until 1996-1997. Until well after the
> 1998, most users considered the ARM as the reference, not the
> ISO standard, simply because most compilers implemented
> something much closer to the ARM than to the ISO standard.

I think that was my point, earlier, but it doesn't hurt repeating.

>> Programs using the earlier
>> bind-temporary-to-reference-to-non-const could still compile
>> and in that sense be valid (for a given compiler), for the
>> intention was to "fade out" use of that feature.
>
> In 1991, yes. The rule was changed before the ARM, and by 1991,
> the ARM was rapidly becoming the definition of what was legal
> and valid C++. The rule wasn't present in earlier versions of
> "The C++ Programming Language", however, which was the reference
> before the ARM.
>
>> So your C++ programs written between 1991 and 1998 could get
>> away with being valid for the compiler(s) used, but invalid
>> wrt. the "reference manual", and neither valid nor invalid
>> wrt. to any standard, not yet existing.
>
> A program which bound a temporary to a non-const reference
> wasn't valid or legal in 1991.

Again (but with suitable reinterpretation of "valid" or "legal" in the
sense it seems you're using these words), I think that was *my* point,
in response to your statement implying that you had bound temporaries to
non-const references in programs you made between the years 1991 and
1998, programs that by your definition of "legal" C++ were "legal". Hm.

OK James, it doesn't matter much, this.

I think you're writing late in the evening or something.

[snip]
>> So I think there were a number of factors influencing the decision.
>
> As I said, the reason you cited was the reason I'd always heard.
> The example you gave is, in fact, the usual example I've seen.
> I'm quite convinced that it is the explination of why the change
> was made. My critical comment above is limited to your
> statement that you couldn't talk about "legal" and "valid" C++
> before ISO intervened, when we not only could, but did.

Perhaps we're not really disagreeing about anything here except a bit of
terminology.

Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

[...]
> >>>> Sorry, that's bull. It makes no sense to talk about "valid"
> >>>> (or "legal") C++ before standardization.
> >>> You're either being intentionally obtuse, or just playing
> >>> stupid.
> >> Are you really sure you want to go that road, James?
> >> First posting a meaningless looks-like-a-clarification, then calling
> >> names when you're taken up on it?
> > First, I don't think the clarification was meaningless, because
> > I've consistently encountered people who misunderstood the issue
> > when it was presented in that way. And second, the attack is
> > less ad hominim than a constatation concerning one particular
> > statement, or way of reasoning. You statement "It makes no
> > sense to talk about "valid" (or "legal") C++ before
> > standardization" is simply ridiculous, and I know you know
> > better. So I have to suppose that you're making it for some
> > sort of rhetorical reason: being intentionally obtuse, playing
> > stupid (since I know you're not), or trying to provoke some sort
> > of reaction I can't see.
> It really doesn't make sense. Different compilers implemented
> different languages.

No more so than today. You had a more or less formal
specification (from AT&T, rather than from ISO), a number of
implementations with more or less errors (rather more, back
then, but I don't know of any compiler today without any errors
either), and a few implementations which decided that they knew
better, and intentionally implemented something different (but
less than today---about the only compiler today which even tries
to respect the standard is EDG).
> E.g., Borland's Turbo C++ implemented virtual calls from
> constructors as they work in Java today, and IIRC Microsoft's
> Visual C++ (mid-90's) didn't have the exception classes
> specified by the draft.

In the mid-90's, no one (or almost no-one) had exceptions.

As I said, templates and exceptions were more or less considered
experimental extensions, weren't considered part of the
"language", and weren't used if you were trying to be portable.

Again, how does that differ from today? We have a specification
for templates, but only EDG even tries to implement it.
> >>> So what was the language in which I wrote valid and legal
> >>> programs between 1991 (when I first started working
> >>> intensively in C++) and 1998 (when the standard was
> >>> adopted).
> >> Assuming you used more than one compiler or one compiler
> >> with more than one set of options, the languages you used
> >> were not standard C++, and they were not one language:
> >> they were a number of slightly different languages,
> >> conforming in general to Bjarne Stroustup's "reference
> >> manual" for C++.
> > I was there, and the ARM was taken very much as a
> > "standard". And with the exception of g++ (which really was
> > a different language at the time), conformance was generally
> > better than conformance to the ISO standard today. (Note
> > that the chapters in the ARM on templates and exceptions
> > were considered more or less experimental, and were not
> > treated as part of the de facto standard.)
> Well, there you have it: in order to come with anything
> resembling a common well-defined language you have to resort
> to a subjective view of which parts of the ARM -- or draft
> standard -- were significant.

Maybe those parts which the author said were significant, and
not experimental? Or simply those parts which consensus had
adopted.

The fact remains that it was easier to write portable C++, which
would be accepted by all compilers, in 1990, than it is today.

[...]
> > Again, I was there, and there was no ISO
> > standard until 1998. And the text that would be the standard
> > didn't really stabilize until 1996-1997. Until well after the
> > 1998, most users considered the ARM as the reference, not the
> > ISO standard, simply because most compilers implemented
> > something much closer to the ARM than to the ISO standard.
> I think that was my point, earlier, but it doesn't hurt
> repeating.

That may have been what you wanted to say, but it's not what you
said. What you said was that there was no such thing as C++
before the standard. That talking about "legal" and "valid" C++
didn't make sense (although everyone using C++ back then did,
and we knew what we were talking about).

[...]
> >> So your C++ programs written between 1991 and 1998 could get
> >> away with being valid for the compiler(s) used, but invalid
> >> wrt. the "reference manual", and neither valid nor invalid
> >> wrt. to any standard, not yet existing.
> > A program which bound a temporary to a non-const reference
> > wasn't valid or legal in 1991.
> Again (but with suitable reinterpretation of "valid" or
> "legal" in the sense it seems you're using these words), I
> think that was *my* point, in response to your statement
> implying that you had bound temporaries to non-const
> references in programs you made between the years 1991 and
> 1998, programs that by your definition of "legal" C++ were
> "legal". Hm.

Woah. I didn't say that it was "valid" or "legal" in 1991. I
said that there was a time in the past when it was valid and
legal. That time is definitly before 1990: it was valid and
legal when the first edition of "The C++ Programming Language"
appeared, but the rule was changed sometime in the late 1980's.
> [snip]
> Perhaps we're not really disagreeing about anything here
> except a bit of terminology.

Isn't that usually the case with us. (Except for iostream,
of course.)

On Dec 15, 9:50 am, George2 <> wrote:
> Hello everyone,
>
> This is my understanding of non-const reference, const reference and
> their relationships with lvalue/rvalue. Please help to review whether
> it is correct and feel free to correct me. Thanks.
>
> 1. A const reference can be binded to a rvalue, for example, a
> temporary object. And the "life" of the temporary object is guaranteed
> to be extended and we can safely operate through the const-reference.
>
> 2. A non-const reference can not binded to a rvalue, I think the
> reason is rvalue is not addressable? And we can not change the rvalue
> through its reference? Are there any other reasons? I am not quite
> sure whether my understanding is fully correct. Since there are some
> non-modifiable lvalues (so we do not always need to modify values
> through its reference). I am still studying what is the reason in
> essence in compiler why a non-const reference can not be binded to a
> rvalue.
>
> 3. Both const and non-const reference can be binded to a lvalue.
>
> thanks in advance,
> George

References are always const. There is no non-const reference... in
fact reference is a kind of a const pointer which has to be
initialized and once initialized can't be changed or modified...

Share This Page

Welcome to The Coding Forums!

Welcome to the Coding Forums, the place to chat about anything related to programming and coding languages.

Please join our friendly community by clicking the button below - it only takes a few seconds and is totally free. You'll be able to ask questions about coding or chat with the community and help others.
Sign up now!