Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Elementary question on references.

128 views
Skip to first unread message

peps...@gmail.com

unread,
Jul 7, 2015, 11:03:41 AM7/7/15
to
Textbooks often say things like "int& x = y; simply means that x is an alias for y."

However, this is ambiguous (to me). Take the following case. std::vector<int> vec; /* ..... */ int index = 5; int& ref = vec[index];

Is ref an alias for vec[5] or for vec[index]? In other words if index changes from 5 to 6, does ref now refer to vec[6]? Or does ref always refer to vec[5]?

Of course, I could just test it, but I would think there's a simple way of thinking about it that makes the answer apparent and unambiguous.

It's clear to me that if we write int& i = index; int& clearRef = vec[i]; then surely clearRef always refers to vec[index] however index changes. But the previous case is unclear to me.

Thank you very much for your help.

Paul
Message has been deleted

Alf P. Steinbach

unread,
Jul 7, 2015, 12:19:18 PM7/7/15
to
On 07-Jul-15 5:02 PM, peps...@gmail.com wrote:
> Textbooks often say things like "int& x = y; simply means that x is an
> alias for y."
>
> However, this is ambiguous (to me). Take the following case.
> std::vector<int> vec; /* ..... */ int index = 5; int& ref = vec[index];
>
> Is ref an alias for vec[5] or for vec[index]? In other words if index
> changes from 5 to 6, does ref now refer to vec[6]? Or does ref always refer
> to vec[5]?

Good question.

In C++ a reference refers to the result of the evaluation of the
initializer expression. But (as I recall) due to a sloppy formulation of
the specification of an early version of the Algol language, it ended up
with so called "call by name" where an argument expression effectively
was substituted into the called routine at each place the formal
argument name was used. It made for both interesting programming,
interesting compiler techniques, and superb inefficiency.

You can think of a C++ reference

T& r = expr;

as

T* const _p = &expr;

with a

#define r (*_p)

which explains most properties, except that since a macro definition
doesn't respect scopes it can't really do the job.

For more discussion based on that point of view see the FAQ items about
references, at <url: https://isocpp.org/wiki/faq/references>.

Where you need something akin to a reference to an expression, like an
Algol call by name formal argument, you can use a named C++ lambda
expression.

vector<int> v;
int i;
auto const r = [&]() -> int& { return v[i]; }

i = 42; r() = 12345;


Cheers & hth.,

- Alf

--
Using Thunderbird as Usenet client, Eternal September as NNTP server.

Öö Tiib

unread,
Jul 7, 2015, 1:16:33 PM7/7/15
to
On Tuesday, 7 July 2015 18:03:41 UTC+3, peps...@gmail.com wrote:

Alf already answered rest of it well enough.

> Of course, I could just test it, but I would think there's a simple way of thinking
> about it that makes the answer apparent and unambiguous.

It is always worth testing when you think you understood something
correctly. If you suspect that you did not understand it then the tests
may also lie to you. Better ask or read it over from other textbook.

For example you might want to be particularly careful with references
to elements of vector since lot of operations that are done later with
vector may invalidate references. Invalid references will often appear
to work with existing C++ compilers.

Somewhat safer is to use iterators to elements of vector. These tend to
have debug versions that fail illegal usages with runtime errors instead
of appearing to work. So if you test with such debug version then it is
less likely to become mislead by test results.

Vir Campestris

unread,
Jul 7, 2015, 4:29:49 PM7/7/15
to
On 07/07/2015 18:16, Öö Tiib wrote:
> It is always worth testing when you think you understood something
> correctly. If you suspect that you did not understand it then the tests
> may also lie to you. Better ask or read it over from other textbook.
>
> For example you might want to be particularly careful with references
> to elements of vector since lot of operations that are done later with
> vector may invalidate references. Invalid references will often appear
> to work with existing C++ compilers.
>
They'll work up to the moment you are demonstrating your code to someone
important. DAMHIK... And I don't expect that to change. Making all
iterators fail, even if the memory is used for something else, is bound
to be slow.

> Somewhat safer is to use iterators to elements of vector. These tend to
> have debug versions that fail illegal usages with runtime errors instead
> of appearing to work. So if you test with such debug version then it is
> less likely to become mislead by test results.

In my experience even the debug ones won't fail _all_ the illegal
usages. But they do help a lot.

Andy

Louis Krupp

unread,
Jul 8, 2015, 1:55:16 AM7/8/15
to
With respect to your last example, I'm not sure exactly what you mean
by "vec[index] however index changes." Does your understanding match
the result of running the following?

Code:
==============
#include <iostream>

int main()
{
int index = 0;
int& i = index;
int vec[] = {1, 2};
int& clearRef = vec[i];

std::cout << clearRef << "\n";

index = 1;
std::cout << clearRef << "\n";

return 0;
}
==============

Result:
==============
1
1
==============

Louis

Paul

unread,
Jul 8, 2015, 2:50:23 AM7/8/15
to
Thanks, Louis. No, this doesn't match my understanding. I should do more testing, rather than just assuming things. I don't understand this result at all. I would have thought vec[i] means "take the nth component of vec where n is the integer to which i refers". Hence I expect vec[i] to change from vec[0] to vec[1] whenever index changes from 0 to 1. Why does this not happen? I suppose that, if I do want this behaviour, the best technique is via lambda functions. Is that correct?

Thank you,

Paul

Louis Krupp

unread,
Jul 8, 2015, 3:19:29 AM7/8/15
to
On Tue, 7 Jul 2015 23:50:10 -0700 (PDT), Paul <peps...@gmail.com>
wrote:
Beats me. I've never used lambda functions.

As I understand it, when you declare clearRef like this:

int& i = index;
int& clearRef = vec[i];

clearRef becomes an alias for the element of vec specified by the
value of i at the time clearRef is declared. Since i is an alias for
index, it's the same as saying:

int& clearRef = vec[indexi];

If index is 0 when clearRef is declared, clearRef becomes an alias for
vec[0], and subsequent changes to index or i don't change clearRef.

The following might help:

Code:
==============
#include <iostream>

int main()
{
int index = 0;
int& i = index;
int vec[] = {1, 2};
int& clearRef = vec[i];

std::cout << vec[i] << "\n";
std::cout << clearRef << "\n";

index = 1;
std::cout << vec[i] << "\n";
std::cout << clearRef << "\n";

return 0;
}
==============

Result:
==============
1
1
2
1
==============

Louis

Rosario19

unread,
Jul 8, 2015, 3:22:59 AM7/8/15
to
On Tue, 7 Jul 2015 08:02:36 -0700 (PDT), peps...@gmail.com wrote:

>Textbooks often say things like "int& x = y; simply means that x is an alias for y."
>
>However, this is ambiguous (to me). Take the following case.
>std::vector<int> vec; /* ..... */ int index = 5; int& ref = vec[index];
>
>Is ref an alias for vec[5] or for vec[index]?
for me

int &i=y;

means &i=&y;

so i is what contain &y

for me &ref is &(vec[5]) or vec+5 so ref=vect[5]

i don't know if i make one error

Öö Tiib

unread,
Jul 8, 2015, 3:37:58 AM7/8/15
to
It feels that you expect reference to be alias of expression. That
is not true, reference is always reference to concrete object.
On case of 'int&' it becomes reference to some int when defined
and stays like that forever.

> Hence I expect vec[i] to change from vec[0] to vec[1] whenever index
> changes from 0 to 1. Why does this not happen?

It does happen, expression 'vec[i]' will evaluate to reference of i-th
element of vec. Just that references can not be used as aliases
of such expressions.

> I suppose that, if I do want this behaviour, the best technique
> is via lambda functions. Is that correct?

Yes, Alf already did show how to declare lambda as alias to expression
'v[i]' and how to use it.
Message has been deleted

Alf P. Steinbach

unread,
Jul 8, 2015, 12:12:56 PM7/8/15
to
On 08-Jul-15 3:32 PM, Stefan Ram wrote:
> Öö Tiib <oot...@hot.ee> writes:
>> It feels that you expect reference to be alias of expression. That
>> is not true, reference is always reference to concrete object.
>
> At least an /lvalue/ reference.
>
> There can be rvalue references to function type (8.3.2).

Yes, and there can be ordinary C++03 reference to function type, also.

Unfortunately Visual C++ does not support implicit lambda conversion to
function reference -- it complains about all the Microsoft calling
convention possibilities that it thinks constitute an ambiguity -- so
still at this point in time the syntax gets pretty awkward:

<code>
#include <iostream>

void invoke( void (&f)() )
{
f();
}

void rinvoke( void (&&f)() )
{
f();
}

void foo() { std::cout << "foo\n"; }

auto main() -> int
{
invoke( foo );
// invoke( *[]{ std::cout << "lambda 1\n"; } ); // Works
with g++ 5.1
invoke( *static_cast<void(*)()>( []{ std::cout << "lambda 1\n"; } )
); // VC 2015

rinvoke( foo );
rinvoke( *static_cast<void(*)()>( []{ std::cout << "lambda 2\n"; } ) );
}
</code>

I suspect that this code is formally invalid because there's no cast to
rvalue reference, and so the * dereferencing is an lvalue expression
that shouldn't bind to an rvalue reference. But both g++ and VC accept
this. So possibly there's something I didn't think of.

Lőrinczy Zsigmond

unread,
Jul 13, 2015, 2:43:12 AM7/13/15
to
On 2015-07-07 17:02, peps...@gmail.com wrote:
> Textbooks often say things like "int& x = y; simply means that x is an alias for y."
>
> std::vector<int> vec;
> /* ..... */
> int index = 5;
> int& ref = vec[index];
>
> Is ref an alias for vec[5] or for vec[index]?

Note: references aren't pointers, say the C++-fanboys.
Nonetheless, they are pointers, immutable pointers with special syntax.
So with assignments like this you can very easily get a dangling
pointer: if you add/or delete elements to 'vec', address of vec[5]
might be changed (cf: realloc), so 'ref' will point to an invalid
address.

Öö Tiib

unread,
Jul 13, 2015, 7:20:56 AM7/13/15
to
On Monday, 13 July 2015 09:43:12 UTC+3, Lőrinczy Zsigmond wrote:
> On 2015-07-07 17:02, peps...@gmail.com wrote:
> > Textbooks often say things like "int& x = y; simply means that x is an alias for y."
> >
> > std::vector<int> vec;
> > /* ..... */
> > int index = 5;
> > int& ref = vec[index];
> >
> > Is ref an alias for vec[5] or for vec[index]?
>
> Note: references aren't pointers, say the C++-fanboys.
> Nonetheless, they are pointers, immutable pointers with special syntax.

That feels oversimplification since there are some other important
differences besides immutability ... worth to note like ... no null references,
no references of references, no arrays of references, no pointers to
references and reference to temporary can extend life-time of that
temporary.

Such additional constraints can make references safer to use (for
programmer) and simpler to optimize that usage (for compiler) than
pointers.

Bo Persson

unread,
Jul 13, 2015, 8:45:56 AM7/13/15
to
On 2015-07-13 08:41, Lőrinczy Zsigmond wrote:
> On 2015-07-07 17:02, peps...@gmail.com wrote:
>> Textbooks often say things like "int& x = y; simply means that x is
>> an alias for y."
>>
>> std::vector<int> vec;
> > /* ..... */
> > int index = 5;
> > int& ref = vec[index];
>>
>> Is ref an alias for vec[5] or for vec[index]?
>
> Note: references aren't pointers, say the C++-fanboys.
> Nonetheless, they are pointers, immutable pointers with special syntax.

The similarity between a pointer and a reference is that they are both
most often implemented by storing the address of an object. That doesn't
mean that they are the same in any other way.

You wouldn't say that all other types are the same, because they all
store bits. Would you?


Bo Persson




Message has been deleted

Lőrinczy Zsigmond

unread,
Jul 13, 2015, 2:44:37 PM7/13/15
to
On 2015.07.13. 18:40, Stefan Ram wrote:
> =?UTF-8?B?TMWRcmluY3p5IFpzaWdtb25k?= <zs...@nospam.for.me> writes:
>> references
> ...
>> are pointers, immutable pointers with special syntax.
>
> Then, a variable like »i« in
>
> { int i = 0; ... }
>
> also is an »immutable pointer with special syntax«.

Sure. Provided it contains an address and its value cannot be changed.

Öö Tiib

unread,
Jul 13, 2015, 5:03:58 PM7/13/15
to
Reference is not said to be object that contains an address of object
(or function). Reference is not object at all unlike pointer. It is
said to be bound to refer to some object (or function) at initialization
but standard does not say how.

It is not empty propaganda of "C++ fanboys". It may be address, but
when we look into code generated by compilers then reference to local,
automatic storage variable is usually there as offset to stack (like
that automatic storage variable itself).

Jorgen Grahn

unread,
Jul 16, 2015, 1:58:36 PM7/16/15
to
On Tue, 2015-07-07, Alf P. Steinbach wrote:
> On 07-Jul-15 5:02 PM, peps...@gmail.com wrote:
>> Textbooks often say things like "int& x = y; simply means that x is an
>> alias for y."
>>
>> However, this is ambiguous (to me). Take the following case.
>> std::vector<int> vec; /* ..... */ int index = 5; int& ref = vec[index];
>>
>> Is ref an alias for vec[5] or for vec[index]? In other words if index
>> changes from 5 to 6, does ref now refer to vec[6]? Or does ref always refer
>> to vec[5]?
>
> Good question.
>
> In C++ a reference refers to the result of the evaluation of the
> initializer expression. But (as I recall) due to a sloppy formulation of
> the specification of an early version of the Algol language, [...]

Etc. In C++ -- (and all real languages. except pure pre-processor
languages like cpp[0]) -- expressions are evaluated where they are, in
their current context. So "index" is 5, and "ref" is a reference to
vec[5], whatever that is at that point in time. Like any other
reference into a std::vector, it's vulnerable to invalidation, though.
For example, if you add enough elements to "vec" to force it to
reallocate itself, "ref" will point to something crazy and
unpredictable. If you don't it's just a sane reference to vec[5].

/Jorgen

[0] cpp and make are the only remaining languages with this property
that I can think of. Maybe m4 as well. Too bad that one of them
is embedded into every C and C++ compiler ...

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
0 new messages