What is definition of reference type? - c++

How do you define (explain) in a formal and strict way what is reference type in C++?
I tried to google, and looked into Stroustrup's "The C++ Programming Language", but I don't see definition of this concept there.

A reference is an alias, an alternate name for an object. It is not an object itself (and in that way is not a pointer, even if some of their uses overlap with uses of pointers).
References have certain limitations to their handling, related to their non-objectness. For example, you can't create an array of references. They have to be initialized (bound, seated) as soon as they are declared, since they can't possibly exist without an object to alias.
You can however store them, and they obey the rules of automatic variables or member variables. One of their uses is to poke through C++'s pass-by-value function calls.
Note that const references have a neat side-effect of being aliases : when bound to a temporary (i.e unnamed) object, they give said object a name, and therefore extend its lifetime to that of the reference itself.
{ // Block scope
Foo fooVal = makeFoo(); // Say makeFoo() returns a (temporary, unnamed) Foo
// Here the temporary Foo is dead (fooVal is a copy).
// Foo &fooRef = makeFoo(); // Error, reference is non-const
Foo const &fooCRef = makeFoo(); // All good
// ...
// The second temporary is still alive
fooCRef.doSomethingFunny(); // Works like a charm !
} // The second temporary dies with fooRef
Beware though, it is possible (though contrived) to have an object go out of scope with references still pointing to it. You will then have dangling references, which are not to be used anymore (doing so would be Undefined Behaviour).
Foo *fooPtr = new Foo; // Here is a Foo
Foo &fooRef = *fooPtr; // Here is an alias for that Foo
delete fooPtr; // Here is the end of that Foo's life
fooRef.doSomethingFunny(); // Here comes trouble...

Regarding
” How do you define (explain) in a formal and strict way what is reference type in C++?
the C++11 standard gives the following formal and strict definition of a reference type in its
§8.3.2/1
” In a declaration T D where D has either of the forms
& attribute-specifier-seqopt D1
&& attribute-specifier-seqopt D1
and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T,” then the type of the
identifier of D is “derived-declarator-type-list reference to T.”
However, if you’re more interested in what a C++ reference practically is (apart from the colloquial use of the term), then check the definition of its meaning in an expression,
§5.5
” If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to
any further analysis. The expression designates the object or function denoted by the reference, and the
expression is an lvalue or an xvalue, depending on the expression
Effectively this means that a reference acts as an alias.
You can think of a reference as an automatically dereferenced const pointer, which explains most of the behavior except that a reference doesn't necessarily occupy storage (the compiler may be able to optimize it away completely).

According to some experts' views reference types are not C++ references per se, but in contrast to value types. I present two slightly differing definitions - of value types and of reference types.
https://abseil.io/blog/20180531-regular-types
The first is a blog post by Titus Winters, chair of the C++ subcommittee responsible for the C++ standards library.
According to Titus Winters, the difference between a value type and a reference type is the copy behaviour. When you copy an instance of a value type, you get two independent objects, which are equal first, but may differ after the modification of one of both. When you copy a reference type, you get two objects, which refer to the same data.
Reference types do not own their data. Some reference types allow modifying the referred-to data (e.g. span), some do not (e.g. string_view). Both examples given are quite useful for function parameter passing. The caller of the function assures (by convention) that the underlying data of the reference types is not destructed during the duration of the function call (as is also the case with plain C++ references).
https://learn.microsoft.com/en-us/cpp/cpp/value-types-modern-cpp?view=vs-2019
The Microsoft documentation puts reference types as synonymous to polymorphic types (types with at least one virtual function or member variable), and value types as non-polymorphic. (Non-polymorphic types are called concrete types by Bjarne Stroustrup.)
Value types are about memory and layout control, reference types are about identity.
Value types allow the compiler direct access to the members, reference types need an indirection due to runtime polymorphism.
Reference types according to Microsoft are non-copyable (to prevent slicing).
So the semantics differ, as Titus Winters defines reference types by their actual copy behaviour.

A major difference between C and C++ (other than Objects and Classes!) is references.
A reference is like a const pointer to a variable. Assigning a reference is a bit like using a pointer but with & not * and you don't need to difference. The difference is that you assign an address to a pointer but a variable to a reference variable.
The line below suggests that the value of a is copied into aref. But it is not, instead aref is a reference to the variable a. Once assigned, aref is the same as a. Any changes to aref are changes to a as example below shows
int & aref = a;
#include <stdio.h>
#include "stdafx.h"
int main()
{
int a=9;
int & aref = a;
a++;
cout << "The value of a is %i\n" << aref;
return 0;
}
Also remember that
A reference must always refer to something.NULLs are not allowed.
A reference must be initialized when it is created. An unassigned reference can not exist.
Once initialized, it cannot be changed to another variable.
If it help you please inform me, thanx

Related

Is there an implicit cast from temporary values to objects of type rvalue reference?

Consider this toy example:
struct A { int x; };
int main() {
A&& a=A();
return 0;
}
Is there an implicit cast from temporary values (values of built-in type, and temporary objects) to objects of type rvalue reference?
Does a has an address?
Is there an implicit cast from temporary values (values of built-in type, and temporary objects) to objects of type rvalue reference?
First a nitpick, casts are explicit conversions by definition, so there cannot be an implicit cast. Beyond that, a reference is distinctly not an object type. It may even not require any storage. References are bound to objects. It'd be more appropriate to think about them as alternative names of objects. Rvalue references in particular can only bind to objects of a particular sort. Which are roughly all "nameless" and "temporary" values. We may also cast to an rvalue reference to force an object being designated as "about to expire".
There's however an intricate point here, once an rvalue reference binds to an object, it's no longer "nameless". In particular, this means that by using that reference we call an object "by name" and thus obtain an lvalue. Furthermore, and to coincide with that, binding a reference in block scope to a temporary, prolongs the lifetime of the temporary until the end of the scope. And that brings us to the next point.
Does a has an address?
Yes and no. The refernece itself may or may not require storage, as I said previously. But that's moot, since it's just the name of an object. Taking the address of a reference will yield the address of the object that was bound to it. In this case, it will be the address of the temporary bound to it.

Unsure about a description regarding Reference in C++ Primer

The book said: Because references are not objects, we may not define a reference to a reference.
int ival = 1024;
int &refVal = ival;
refVal = 2;
int ii = refVal;
int &refVal3 = refVal; // isn't this a definition of ref to ref?
int i = refVal;
int &refVal4 = 10;
double dval = 3.14;
int &refVal5 = dval;
However, that line is not an error, because refVal3 is saying it is just another alias for refVal, and refVal is just another name for ival(refVal3 is bound to the object to which refVal is bound to, which is ival)... so both refVal and refVal3 refer to the initializer of ival.
That makes perfect sense, but if that's not a definition of a reference to a reference, just what exactly does the book mean when it mentioned "Because references are not objects, we may not define a reference to a reference." ??
Can someone perhaps give me an example ?
Your understanding is correct.
int &refVal3 = refVal;
This makes refVal3 a reference to the same thing refVal is a reference to. That is, ival.
just what exactly does the book mean when it mentioned "Because
references are not objects, we may not define a reference to a
reference." ?
A reference can only refer to an object. But references are not objects. So a reference cannot refer to a reference. And when the book says this, it doesn't just mean that it's not allowed, and you'll get an error if you try. But you can't even try. There's no syntax for it. Because anything you try to do to a reference, you will actually be doing to the object it refers to, and not to the reference itself.
Can someone perhaps give me an example ?
No. I can't. And that's the point. There's simply no syntax for it.
Reference-to-reference types (like T & &) do not exist in C++.
Where T is an object type (which includes int, as in your example):
You can have (lvalue) references to T. There exists a type T &.
You can have rvalue references to T. There exists a type T &&.
T && is not a reference to a reference; && is a single token and does not mean & &.
You cannot have references to references to T. There are no such types as T & &, T & &&, T && & or T && &&. If you write a declaration that attempts to explicitly name such a type, this is an error.
(Similarly, cv-qualified types like const T& exist, while types like const T & & do not exist.)
You asked for an example. Consider this wrong code:
int main()
{
int ival = 1024;
int &refVal = ival;
int & &refRefVal = refVal; // wrong
}
This is an error because there is no such type as int & &. It would be an error regardless of what I tried to initialize it with.
(Strictly speaking, it is an error because the syntax of the language prohibits it. The standards committee could have chosen to allow me to write int & & and have it mean the same thing as int &--see Reference Collapsing below--but they didn't, which is good, because that would be very confusing.)
When I attempt to compile that wrong code with Clang 3.8, I get:
error: 'refRefVal' declared as a reference to a reference
Other compilers give similar errors. For example, Microsoft Visual C++ gives:
error C2529: 'refRefVal': reference to reference is illegal
When you use a reference, the effect is to use the object it refers to.
References are dereferenced automatically in most contexts where they appear. Anything you try to do to a reference, really you are doing it to the object it refers to. Unlike pointers, there is no operator for dereferencing a reference; in effect the reference is a name for the referenced object.
What you have written (int &refVal3 = refVal;) is not an error, because you are simply initializing a second reference bound to the same object. To see why this is, consider the effect of several of your statements.
Here you create an int, initializing it with the value 1024:
int ival = 1024;
Here you make an lvalue reference, bound to that int object:
int &refVal = ival;
Here you assign 2 to the original int object, because refVal is used as the object to which it refers:
refVal = 2;
Here you create a second int object, initialized with the value of the original object, also because refVal is used as the object to which it refers:
int ii = refVal;
Here you make a second lvalue reference to the original object, also because refVal is used as the object to which it refers:
int &refVal3 = refVal;
Code that looks like it creates a second reference to the first one is, therefore, really creating a second reference to the original object.
This is to say that the reason int &refVal3 = refVal; introduces another reference to the original object--rather than attempting to create a reference to a reference--is that this is just another consequence of refVal being automatically taken to mean the int it refers to.
Reference Collapsing
You can't write types named like T & & yourself, but what about this?
using Ref = int&;
using RefRef = Ref&; // I named this poorly, it's not really a reference to a reference!
This causes the compiler to see that I am trying to make a type alias RefRef to be int& &. The compiler follows the rules of reference collapsing. It collapses the two references into one, so the effect is the same as if I had written:
using RefRef = int&;
This behavior is useful in situations that involve type deduction, such as with templates, both by allowing more code to compile and work as expected than otherwise would, and by facilitating perfect forwarding. (One might argue it also parallels what you observed--when you initialize references from references, you can still never get a reference to a reference, only to an object.)
In no case is there ever anything whose type is reference to reference. The C++ language simply does not have any such types.

Is it legal to modify an object created with new through a const pointer?

So this answer made me think about the scenario where you assign the result of new to a pointer to a const. AFAIK, there's no reason you can't legally const_cast the constness away and actually modify the object in this situation:
struct X{int x;};
//....
const X* x = new X;
const_cast<X*>(x)->x = 0; // okay
But then I thought - what if you actually want new to create a const object. So I tried
struct X{};
//....
const X* x = new const X;
and it compiled!!!
Is this a GCC extension or is it standard behavior? I have never seen this in practice. If it's standard, I'll start using it whenever possible.
new obviously doesn't create a const object (I hope).
If you ask new to create a const object, you get a const object.
there's no reason you can't legally const_cast the constness away and actually modify the object.
There is. The reason is that the language specification calls that out explicitly as undefined behaviour. So, in a way, you can, but that means pretty much nothing.
I don't know what you expected from this, but if you thought the issue was one of allocating in readonly memory or not, that's far from the point. That doesn't matter. A compiler can assume such an object can't change and optimise accordingly and you end up with unexpected results.
const is part of the type. It doesn't matter whether you allocate your object with dynamic, static or automatic storage duration. It's still const. Casting away that constness and mutating the object would still be an undefined operation.
constness is an abstraction that the type system gives us to implement safety around non-mutable objects; it does so in large part to aid us in interaction with read-only memory, but that does not mean that its semantics are restricted to such memory. Indeed, C++ doesn't even know what is and isn't read-only memory.
As well as this being derivable from all the usual rules, with no exception [lol] made for dynamically-allocated objects, the standards mention this explicitly (albeit in a note):
[C++03: 5.3.4/1]: The new-expression attempts to create an object of the type-id (8.1) or new-type-id to which it is applied. The type of that object is the allocated type. This type shall be a complete object type, but not an abstract class type or array thereof (1.8, 3.9, 10.4). [Note: because references are not objects, references cannot be created by new-expressions. ] [Note: the type-id may be a cv-qualified type, in which case the object created by the new-expression has a cv-qualified type. ] [..]
[C++11: 5.3.4/1]: The new-expression attempts to create an object of the type-id (8.1) or new-type-id to which it is applied. The type of that object is the allocated type. This type shall be a complete object type, but not an abstract class type or array thereof (1.8, 3.9, 10.4). It is implementation-defined whether over-aligned types are supported (3.11). [ Note: because references are not objects, references cannot be created by new-expressions. —end note ] [ Note: the type-id may be a cv-qualified type, in which case the object created by the new-expression has a cv-qualified type. —end note ] [..]
There's also a usage example given in [C++11: 7.1.6.1/4].
Not sure what else you expected. I can't say I've ever done this myself, but I don't see any particular reason not to. There's probably some tech sociologist who can tell you statistics on how rarely we dynamically allocate something only to treat it as non-mutable.
My way of looking at this is:
X and const X and pointers to them are distinct types
there is an implicit conversion from X* to const X*, but not the other way around
therefore the following are legal and the x in each case has identical type and behaviour
const X* x = new X;
const X* x = new const X;
The only remaining question is whether a different allocator might be called in the second case (perhaps in read only memory). The answer is no, there is no such provision in the standard.

Pointer to member that is a reference illegal?

Let us say I have:
// This is all valid in C++11.
struct Foo {
int i = 42;
int& j = i;
};
// Let's take a pointer to the member "j".
auto b = &Foo::j; // Compiler is not happy here
// Note that if I tried to get a pointer to member "i", it would work, as expected.
Foo f;
std::cout << f.*b; // Try using the pointer to member
The compiler complains that I cannot take the address of the member because it is a reference. To be precise:
Semantic Issue: Cannot form a pointer-to-member to member 'j' of reference type 'int &'
I know doing this seems pointless, but I am only wondering why it cannot be done.
Why is this impossible?
It cannot be done because you cannot take a pointer to a reference- period.
If you could take a member pointer to a reference, this would be inconsistent with the behaviour of references on the stack. The attitude of C++ is that references do not exist. As such, you cannot form a pointer to them- ever.
For example, &f::a would have to be different to &f::b. And by de-referencing &f::b, you would effectively be achieving a pointer to a reference, which is not allowed.
C++11 standard:
§8.3.3 p3 [dcl.mptr]
A pointer to member shall not point to a static member of a class (9.4), a member with reference type, or “cv void.”
Also, in general:
§8.3.1 p4 [dcl.ptr]
[ Note: There are no pointers to references; see 8.3.2. [...] —end note ]
§8.3.2 p5 [dcl.ref]
There shall be no references to references, no arrays of references, and no pointers to references.
Member pointer (as opposed to a simple pointer to a member) is simply an offset into the structure, not a pointer at all. You can get data through it only in conjunction with the structure itself (or a pointer to a structure): the value of the offset is added to the address of the structure, and the result is dereferenced to produce the value of the member.
Now suppose a member is a reference, so accessing data through it already requires a dereference (compiler hides it from us, but it needs to spit out the corresponding instructions in its output). If C++ were to allow member pointers to references, they'd be of yet another type: an offset that needs to be added to the base, and then dereferenced twice. It is too much work to improve an already obscure feature; prohibiting it is a much better way out.
Allowing you to make a pointer to a reference does not give you any expressive power. There's nothing you can do with such a beast that you can't easily do with a reference or with a pointer. All you get out of it is added complexity.
And making a pointer to a member that is a reference is not allowed for consistency with the rule that forbids pointers to references, and because it adds even more complexity. The designers of the language probably decided that the little gains you get from these was not worth it.
This is totally just my opinion.

Difference between C++ const references and consts?

What is the difference between:
const double& pi = 3.14;
and (no ampersand):
const double pi = 3.14;
They both seem to have the same L and R values so what is the difference?
For your particular example there's no difference.
And that means, no way to tell them apart, whatsoever.
However, since the first binds a reference to a temporary, when the type is of class type the temporary can be of a derived class, e.g. produced by a function! And it then has its destructor properly called at the end of the scope. This little el neato trick is used in ScopeGuard implementations (see the original ScopeGuard article in DDJ, by Petru Marginean and Andrei Alexandrescu -- Petru invented ScopeGuard and Andrei made a more general thing on top).
I once asked Bjarne Stroustrup, who created the C++ language, why the syntax in your first declaration is supported.
And his reply was that it was mostly to have uniform rules (i.e. to not make any special exception for local references as opposed to references as formal parameters). I think at that time neither of us were familiar with ScopeGuard. It's simple in retrospect, but it takes a mind like Petru's, or Andrei's, to come up with something like that! :-)
Cheers & hth.
The important difference with a reference is that a reference itself is inheritly constant. Once the reference itself has been initially assigned to a variable, it can not then reference another variable. All attempts to modify it will modify the variable it refers to. Given this, the const will mean that the reference is a reference to a const int.
const int A;
const int B;
const int& Reference = A;
Reference = B; // Error, the value of A can not be assigned, nor would this *ever* be able to make Reference refer to B.
You can also test this theory about a reference itself being constant like so:
const int& const Reference; // Should give a warning about the second const being redundant.
A bit of clarification about constant references, references and constants for doubles.
Reference
A reference refers to an existing an object and cannot be reseated. That is, once you declare (define) the reference, it will always refer to that item.
Constant Reference
The C++ language allows for declaring of a constant reference. This tells the compiler that the reference will not change. This may be redundant since references cannot be reseated. However, the language syntax allows it.
Constant
A constant is a value, and does not refer to anything.
Optimizations & Substitutions
The compiler is allowed to substitute (replace) a reference to an object, constant or literal with the corresponding object, constant or literal, provided that the compiler can guarantee that no write operations are performed to that object within the scope it is used in. This determination may become difficult when the reference is passed to methods or functions within that scope.
Specifying the const modifier to a reference will make the compiler's job easier for optimizing. The constant reference is a contract with the programmer and user that the reference will not be changed.
const double& is a reference to a constant double, the other one is a constant double. A reference is kind of a const pointer, a pointer that never changes.
In C++ the references are inherently const. Once they have been assigned you can not changes them. They must be both declared and initialized.
The reference isnt const only the value is const, so you should be able reassign referense, that means the following would be ok:
const double& pi = 3.14;
const double pi2 = 2.78;
pi = *(&pi2);