Why const int& ?

T

Travis Parks

Could someone quickly remind me why functions taking ints should
consider passing by constant reference?

I know the constant part allows you to pass literals, but I am trying
to remember what benefit there is to using references instead of
relying on plain copy semantics.

Also, does:

const int&

mean:

int const&

or:

int &const

Finally, what would int const&const mean? Does it make sense to mark
an int as constant, considering by nature it already is? Is this
syntax legal?

Thanks,
Travis Parks
 
M

Marc

Travis said:
Could someone quickly remind me why functions taking ints should
consider passing by constant reference?

For fun? Because you are paid according to the size of the code?
Also, does:

const int&

mean:

int const&
Yes.

or:

int &const

Invalid. If you are thinking of the analogy with pointers, references
are always const.
Finally, what would int const&const mean?
Nothing.

Does it make sense to mark an int as constant, considering by nature it
already is?

Read up on the difference between lvalue and rvalue.
 
I

Ian Collins

Could someone quickly remind me why functions taking ints should
consider passing by constant reference?

Your wouldn't normally pass an int by const reference, but if you are
declaring a template, then const reference ( const T& ) is appropriate.
 
J

Joshua Maurice

Also, does:

const int&

mean:

int const&

or:

int &const

Finally, what would int const&const mean? Does it make sense to mark
an int as constant, considering by nature it already is? Is this
syntax legal?

int const & x -- a reference to const int
const int & x -- a reference to const int
int & const x -- ill formed code that should trigger a compiler error

int const * x -- a (non-const) pointer to const int
const int * x -- a (non-const) pointer to const int
int * const x -- a const pointer to (non-const) int
 
T

Travis Parks

int const & x -- a reference to const int
const int & x -- a reference to const int
int & const x -- ill formed code that should trigger a compiler error

int const * x -- a (non-const) pointer to const int
const int * x -- a (non-const) pointer to const int
int * const x -- a const pointer to (non-const) int

Ah. That clears some things up. A trailing const only makes sense in
terms of pointers, not references.

So, say you had a block of code that looked like this:

vector<int> values;
init(values);

void init(vector<int> & values)
{
vector<int> v;
values = v; // assignment operator
}

How can I tell the compiler a) that I don't want to change the vector
and b) that I don't want the vector to be reassigned?

My guess right now is you handle both a and b the same way, since the
assignment operator modifies the internals of the vector.

Working in languages like C# and Java, where everything is a reference
type, it is strange to think that an assignment modifies the contents
of the original vector (copying v), rather than simply refering both
to the same vector.

On the other hand, pointers work the same way as reference types in
Java and C#, hence the ability to add the extra const onto the end.

Let me know if I'm on the right trail.
 
J

Joshua Maurice

Ah. That clears some things up. A trailing const only makes sense in
terms of pointers, not references.

So, say you had a block of code that looked like this:

vector<int> values;
init(values);

void init(vector<int> & values)
{
    vector<int> v;
    values = v; // assignment operator

}

How can I tell the compiler a) that I don't want to change the vector
and b) that I don't want the vector to be reassigned?

My guess right now is you handle both a and b the same way, since the
assignment operator modifies the internals of the vector.

Working in languages like C# and Java, where everything is a reference
type, it is strange to think that an assignment modifies the contents
of the original vector (copying v), rather than simply refering both
to the same vector.

On the other hand, pointers work the same way as reference types in
Java and C#, hence the ability to add the extra const onto the end.

Let me know if I'm on the right trail.

Sort of. Unfortunately, AFAIK, Java developers decided that "pointer"
was a dirty word and used the word "reference" instead. Java
references really ought to have been called pointers. Java references
have more or less the same semantics as C++ pointers (except of course
no pointer arithmetic, etc.). That is, a C++ pointer is a "region of
memory" distinct from the "region of memory" of the pointed-to thingy.
Same as Java. In C++ parlance, the pointer is an object, and it points
to a separate object.
int x; // an object
int* y = & x; // the pointer object y points to the int object x

A C++ reference is not a distinct object. It is merely another name
for a pre-existing object. Now, as an implementation detail, it's
probably implemented as a pointer, but that's an implementation
detail. You cannot make a const reference (contrast with "reference to
const"). All references are implicitly "const" - all references are
unchangeable. You cannot "reseat" a reference. Once a C++ reference is
created, it "points" to the same object for the reference's lifetime.
Any attempt to reseat the reference invokes undefined behavior (more
or less - IIRC there might be an obscure exception or two - ignore
that for now).

So, for:
void foo(vector<int> * x)
The body of the function can reassign x to point to a different vector
object. The caller's pointer remains unchanged no matter what.
However, the pointed-to object may be changed, and this is visible to
the caller. That is, pointer have "pass by value" semantics, just like
Java references. A change to the C++ pointer object in the body does
not affect the caller, but a change to the pointed-to object does
affect the caller.

void foo(vector<int> & x)
The body of the function cannot reassign x to "point" to a different
vector object. Any attempt to do so is undefined behavior (more or
less - IIRC there might be an obscure exception or two - ignore that
for now). "x" is just another name for an already existing vector
object. Any changes to x will affect the caller.

void foo(vector<int> const * x)
The caller knows that the function body won't modify the vector object
(more or less - const_casts can, and you might be able to obtain a non-
const reference to it through some other means and modify it through
that).

void foo(vector<int> * const x)
The caller doesn't care about this const. This const only affects the
body's local pointer object which the caller does not see.

void foo(vector<int> const & x)
The caller knows that the function body won't modify the vector object
(more or less - const_casts can, and you might be able to obtain a non-
const reference to it through some other means and modify it through
that).

void foo(vector<int> & const x)
Ill-formed code. References are not distinct objects from the "pointed
to" object. They are simply another name for an existing object. The
const there doesn't mean anything.
 
J

Juha Nieminen

Joshua Maurice said:
Sort of. Unfortunately, AFAIK, Java developers decided that "pointer"
was a dirty word and used the word "reference" instead. Java
references really ought to have been called pointers. Java references
have more or less the same semantics as C++ pointers (except of course
no pointer arithmetic, etc.). That is, a C++ pointer is a "region of
memory" distinct from the "region of memory" of the pointed-to thingy.
Same as Java. In C++ parlance, the pointer is an object, and it points
to a separate object.

Actually references in Java are much more abstract than pointers in C++,
even though that might not be immediately apparent.

Not only cannot you perform pointer arithmetic with Java references,
you cannot reinterpret-cast them either, which is actually a more important
limitation than just safeguarding the programmer from mistakes.

The strict rules imposed on Java references allow the JRE to perform
operations that are impossible for a C++ runtime environment to do. For
example, it allows transparent memory compaction and defragmentation
(in other words, the physical location of objects in memory may be changed
by the runtime environment without the refences to them breaking). Granted,
I don't know if any existing JRE does this, but the language fully allows
for it to be done.

This abstraction even allows for the JRE to make runtime safety checks,
such as checking that references are pointing to valid objects (they might
point to invalid objects if the Java binary is corrupted or somehow
ill-formed, possibly on purpose).

This cannot be done in C++ because pointers are literal memory addresses,
and moving an object from one memory location to another will break any
pointers pointing to it. C++ pointers cannot be made similarly abstract as
they are in Java because of all the operations that must be possible to apply
to them (such as conversion to void* and back, or reinterpret-casting to
a completely unrelated pointer type).
 
B

Brian Drummond

In that respect, Java follows an older precedent than C or C++.
Actually references in Java are much more abstract than pointers in
C++,
even though that might not be immediately apparent.

Likewise. ALGOL-W (from about 1963) comes to mind here.

- Brian
 
T

Travis Parks

Sort of. Unfortunately, AFAIK, Java developers decided that "pointer"
was a dirty word and used the word "reference" instead. Java
references really ought to have been called pointers. Java references
have more or less the same semantics as C++ pointers (except of course
no pointer arithmetic, etc.). That is, a C++ pointer is a "region of
memory" distinct from the "region of memory" of the pointed-to thingy.
Same as Java. In C++ parlance, the pointer is an object, and it points
to a separate object.
  int x; // an object
  int* y = & x; // the pointer object y points to the int object x

A C++ reference is not a distinct object. It is merely another name
for a pre-existing object. Now, as an implementation detail, it's
probably implemented as a pointer, but that's an implementation
detail. You cannot make a const reference (contrast with "reference to
const"). All references are implicitly "const" - all references are
unchangeable. You cannot "reseat" a reference. Once a C++ reference is
created, it "points" to the same object for the reference's lifetime.
Any attempt to reseat the reference invokes undefined behavior (more
or less - IIRC there might be an obscure exception or two - ignore
that for now).

So, for:
    void foo(vector<int> * x)
The body of the function can reassign x to point to a different vector
object. The caller's pointer remains unchanged no matter what.
However, the pointed-to object may be changed, and this is visible to
the caller. That is, pointer have "pass by value" semantics, just like
Java references. A change to the C++ pointer object in the body does
not affect the caller, but a change to the pointed-to object does
affect the caller.

    void foo(vector<int> & x)
The body of the function cannot reassign x to "point" to a different
vector object. Any attempt to do so is undefined behavior (more or
less - IIRC there might be an obscure exception or two - ignore that
for now). "x" is just another name for an already existing vector
object. Any changes to x will affect the caller.

    void foo(vector<int> const * x)
The caller knows that the function body won't modify the vector object
(more or less - const_casts can, and you might be able to obtain a non-
const reference to it through some other means and modify it through
that).

    void foo(vector<int> * const x)
The caller doesn't care about this const. This const only affects the
body's local pointer object which the caller does not see.

    void foo(vector<int> const & x)
The caller knows that the function body won't modify the vector object
(more or less - const_casts can, and you might be able to obtain a non-
const reference to it through some other means and modify it through
that).

    void foo(vector<int> & const x)
Ill-formed code. References are not distinct objects from the "pointed
to" object. They are simply another name for an existing object. The
const there doesn't mean anything.- Hide quoted text -

- Show quoted text -

These are really awesome breakdowns. Thank you. I think this is an
interest example too:

void foo(vector<int> const *& x);

This will allow the value in the pointer to be changed, but not the
vector. This would allow the function to change which vector the
caller is looking at. For completeness:

void foo(vector<int> const* const& x);

This will not allow modification of the vector or the pointer.

This really makes things clear. Just FYI, I was asking this question
because I am in the process of designing my own low-level language
that supports pointers and references. I was trying to figure out the
semantics of references and pointers.

I have been struggling on how I want to provide all the power of C
without making other features of the language unnecessarily
complicated. In OOP and functional situations, const-ness, pointers
and references can kill succinctness.

This language needs to be capable of implementing an OS with features
allowing for higher levels of abstraction. It is hard to implement an
OS without the ability to manipulate memory on a byte-by-byte basis.

Thanks again!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top