I'm a rusty amateur C++ programmer coming back after along time and moving on from OpenGL 2.0 to Vulkan.
I'm trying to understand the code behind the tutorials I'm reading not just copy, but don't understand the & part of the following:
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
Why is the & after exception? My understanding is the pointer is usually after the variable and the address before it, such as:
int* pintVar;
pintVar = &intVar;
Has this got something to do with binding a constant reference 'exception' to a temporary object 'e'?
As you can see I'm trying to research/google it but not totally understanding it or why.
Any help would be appreciated.
& has different meanings depending on context. In a declaration, it means reference to. e.g.
int a = 42;
int &b = a; // b is a reference to a
// b is essentially an alias of a (they both have the same address, for example)
// i.e. changes to b will be reflected in a, and vice versa
Here's some reference that explains this in more depth.
When & is used on an already existing variable, this means address-of. e.g.
int a = 42;
int *b = &a; // b points to a (i.e. b holds the address of a).
So in your example, e is a const reference to whatever exception is passed in (since the parameter of a function declares a variable).
Analogous question:
int* pintVar;
"Why is the * after int? What is the indirection operator doing there? Why isn't it before the variable name such as in here?"
int intVar = *pintVar;
Well, you see * symbol has multiple meanings. Perhaps you already understand this: Within a compound type name, it signifies a pointer type. Within an expression it signifies an operator. It can be either the unary indirection operator (*pintVar) or the binary multiplication operator (a * b).
In the exactly same way, & symbol has multiple meanings. Within a compound type name, it signifies a reference type. Within an expression it signifies an operator. It can be either the unary addressof operator (&intVar) or the binary bitwise AND operator (a & b).
So, const T& is a reference to const T, just like const T* would be a pointer to const T.
Both reference and pointer are forms of indirection, and are quite smilar. Their differences are:
Pointers are objects, references are not objects
Because references are not objects, there is no way to take the address of a reference, and there is no such thing as a pointer to reference or a reference to reference.
There are also no arrays of references.
A (non-const) pointer can be assigned to point to another object. A reference is bound to a single object for its entire lifetime.
Pointer can be null, a reference cannot be.
You must indirect through a pointer explicitly using an indirection operator. All operations on a reference implicitly indirect through the reference, and apply to the referred object instead.
Assignment of reference is assignment of the referred object.
Taking the address of a reference variable is taking address of the referred object.
Pointers are iterators for arrays; You can do pointer arithmetic to iterate the elements. Adding one to a pointer results in pointer to the successive array element. There is no reference arithmetic. Because of the implicit indirection, adding one to reference adds one to the referred object.
Has this got something to do with binding a constant reference 'exception' to a temporary object 'e'?
There are many right words there, but I don't understand what you are trying to mean by them.
e is a variable. The type of the variable is const std::exception& i.e. reference to constant exception. Upon throw, the reference is bound to the exception object that was thrown.
Related
I am currently learning C++ from C++ Primer, and it explains how a reference is an alias to another variable name. It also explains how a pointer points to another variable. It states that the difference between a pointer and a reference is that pointers can be reassigned and references can't.
In the following code example, what can I do with the pointer or reference that I can't do with the other?
double pi = 3.14;
double &piRef = pi;
double *const piPnt = π
//both of these examples are valid and do the same thing
piRef = 3.14159;
*piPnt = 3.14159;
//however, if I attempt to reassign what the pointer points to, it is illegal.
//this is the same as with a reference, as a reference can't be reassigned either
double tau = 6.28;
piPnt = τ
I am aware of the internal differences of each (such as that a pointer is an object, a reference isn't). I am interested in how those differences matter to the programmer beyond a slightly different syntax. As such, this is not a duplicate of this question in which the accepted answer only talks about internal differences.
From a functional point of view pointers and references are indeed the same thing... they reference an object and are not a copy of that object.
The only real difference in addition to not being able to rebind a reference is that a pointer can be NULL (i.e. it can point to nothing) while a reference is assumed to always reference an object.
You technically can actually end up with a reference that is referencing no object (e.g. passing *p to a function expecting a reference where p is the null pointer) but this is "undefined behavior".
In other words pointers are more "flexible" than references and this allows the compiler to ignore
That a reference can change the object it's referencing
That a reference can have no object
And this can in some cases produce faster code (however for the second point de-referencing a null pointer is undefined behavior and not a runtime error; the compiler therefore is not mandated to generate code that does something special in this case: that a pointer can actually point to no object is indeed irrelevant from a code generation point of view because it's in the contract between programmer and compiler that this will never happen).
The "price" to pay for the added flexibility of rebinding and having NULLs is that the syntax is (somewhat gratuitously) more annoying.
If the pointer cannot be reassigned (because the pointer itself is const) then there are no practical differences whatsoever except for the more verbose-but-explicit syntax. This because despite being an object a const-declared pointer cannot be altered even using aliasing.
While from a syntactic point of view you can take the address of the const pointer, cast the address to an address of a non-const pointer and change the value pointed to, such an operation would be undefined behavior and whatever happens (e.g. ignoring the assignment) the compiler is going to be right if taken to court :-)
what can I do with the pointer or reference that I can't do with the other?
References allow you to write certain constructors and overload operators:
class X
{
// copy constructor
X(const X& a);
// move constructor
X(X&& a);
// copy assignment operator
X& operator=(const X& a);
// move assignment operator
X& operator=(X&& a);
}
(Indeed, operator overloading was the motivating use case for introducing references into C++.)
What is often overlooked is the fact that modern C++ distinguishes between X& (a reference to an lvalue) and X&& (a reference to an rvalue), but there is no such thing as a pointer to an rvalue.
what can I do with the pointer or reference that I can't do with the
other?
double *const piPnt = π
The above statement
marks piPnt as a read only variable in memory layout
So, piPnt = &xyz would throw an error now.
But changing the value at the address the pointer points to is still valid.
That is , *piPnt = 56 is fine.
Const Pointers are useful in embedded systems that need to refer to the same memory (port mapping). It's a one time mapping and constant pointers are helpful here.
Now with regards to references:
double &piRef = pi;
You cannot reinitialize a reference in C++. You can assign different value to the object it refers to. This is one and the same object for that reference forever. And this is what you did in your example.
piRef = 3.14159;
A reference cannot be changed to refer to another object after
initialization. Note that initialization of a reference is treated
very differently from assignment to it. Argument passing (5.2.2) and
function value return (6.6.3) are initializations.
Some places where references are useful:
Pointers cannot point to temporaries, the standard expressly forbids doing it. References can bind to temporaries.
A pointer can be NULL while a reference is assumed to always reference an object. You can still return null from a function returning a reference, the compiler would not complain about it, but that is suicidal.
Read a lot of differences between pointers & references.
Here is a brief description of what i learned.
1. Memory is allocated when a pointer is defined. A reference however, is a name alias & hence no memory is allocated for it(Is it correct?).
2. Reference is bound to be initialized at the time of definition because, a reference is implemented with a constant pointer & hence cannot be made to point to the other object.
A pointer however, is not necessary to be initialized at the time of definition & hence can also be changed to point to some other object.
3. A reference automatically gets de-referenced. When you write cout << p;
It is automatically de-referenced by the compiler & treated as cout << *p; by the compiler.
Here, p is the reference.
A reference to a reference is not possible.Whenever, you declare a reference to a reference, its actually the reference to the same variable.
e.g.
int i;
int &r1=i;
int &r2=r1; <-------------------2
Compiler interprets the statement 2 as:
int &r2=(*r1)
and (*r1) is nothing but the variable i itself.
A pointer to a pointer is however possible.
5. Array of pointer is possible while array of references is not possible(Why?).
6. Address of pointer is possible. Address of reference is not possible. It gives of the address of the variable.
7. There are situations where you are bound to use references.You cannot use pointers there.
Consider the below example:
A a=b+c;
Where a,b,c are objects of class A.
The operator '+' is overloaded as follows:
const A& operator+(const A& o)
{
return A(i+o.i);
}
See sample code here: http://ideone.com/Q0pE1
Here the reference in the argument list is used to save the memory footprints.
You cannot use pointer in the argument list as you are bound to pass the address of object in the operator function.
A a=&b + &c;
However, if pointer is used in the parameter list, then we will end up adding the addresses rather than object itself.
I want to know that is there any other point that i am missing?
When should one go for pointer & when for reference?
Memory is allocated when a pointer is defined. A reference however, is a name alias & hence no memory is allocated for it
What do you mean by "memory is allocated?" If you mean a heap allocation, as with new or malloc or whatever, no:
int val = 5;
int *pVal = &val; //No dynamic memory allocation.
A pointer has a size, in the same way that int has a size. But that's different from an "allocation".
Reference is bound to be initialized at the time of definition because, a reference is implemented with a constant pointer & hence cannot be made to point to the other object.
No, a reference is bound at initialization time because that's how references work. They are references to objects. The language states that it is impossible for them to not be bound, and it is impossible for their binding to change later. Therefore, it is necessary that references are bound when they are initialized.
How a compiler implements references is entirely irrelevant.
A reference automatically gets de-referenced.
No. There is nothing to de-reference. A reference is merely another name for an already existing object. That's all.
Array of pointer is possible while array of references is not possible(Why?).
Because a reference has to be bound when it is initialized. And it's not possible to give each member of an array a separate object to be bound to. Thus, you would need some step between the creation of the array and the binding of the reference. Which is not allowed.
Address of pointer is possible. Address of reference is not possible. It gives of the address of the variable.
A reference is another name for an already existing object. You can't get the address of a name; you can only get the address of an object.
There are situations where you are bound to use references.
There's nothing stopping you from overloading operator+ for pointers to the types:
A operator+(const A *lhs, const A *rhs) {...}
Of course, this is a non-member function.
Oh, and as a bonus:
const A& operator+(const A& o)
{
return A(i+o.i);
}
This is broken. You're returning a const& to a temporary you create. You should be returning it by value.
what happens when you dereference a pointer when passing by reference to a function?
Here is a simple example
int& returnSame( int &example ) { return example; }
int main()
{
int inum = 3;
int *pinum = & inum;
std::cout << "inum: " << returnSame(*pinum) << std::endl;
return 0;
}
Is there a temporary object produced?
Dereferencing the pointer doesn't create a copy; it creates an lvalue that refers to the pointer's target. This can be bound to the lvalue reference argument, and so the function receives a reference to the object that the pointer points to, and returns a reference to the same. This behaviour is well-defined, and no temporary object is involved.
If it took the argument by value, then that would create a local copy, and returning a reference to that would be bad, giving undefined behaviour if it were accessed.
The Answer To Your Question As Written
No, this behavior is defined. No constructors are called when pointer types are dereferenced or reference types used, unless explicitly specified by the programmer, as with the following snippet, in which the new operator calls the default constructor for the int type.
int* variable = new int;
As for what is really happening, as written, returnSame(*pinum) is the same variable as inum. If you feel like verifying this yourself, you could use the following snippet:
returnSame(*pinum) = 10;
std::cout << "inum: " << inum << std::endl;
Further Analysis
I'll start by correcting your provided code, which it doesn't look like you tried to compile before posting it. After edits, the one remaining error is on the first line:
int& returnSame( int &example ) { return example; } // semi instead of colon
Pointers and References
Pointers and references are treated in the same way by the compiler, they differ in their use, not so much their implementation. Pointer types and reference types store, as their value, the location of something else. Pointer dereferencing (using the * or -> operators) instructs the compiler to produce code to follow the pointer and perform the operation on the location it refers to rather than the value itself. No new data is allocated when you dereference a pointer (no constructors are called).
Using references works in much the same way, except the compiler automatically assumes that you want the value at the location rather than the location itself. As a matter of fact, it is impossible to refer to the location specified by a reference in the same way pointers allow you to: once assigned, a reference cannot be reseated (changed) (that is, without relying on undefined behavior), however you can still get its value by using the & operator on it. It's even possible to have a NULL reference, though handling of these is especially tricky and I don't recommend using them.
Snippet analysis
int *pinum = & inum;
Creates a pointer pointing to an existing variable, inum. The value of the pointer is the memory address that inum is stored in. Creating and using pointers will NOT call a constructor for a pointed-to object implicitly, EVER. This task is left to the programmer.
*pinum
Dereferencing a pointer effectively produces a regular variable. This variable may conceptually occupy the same space that another named variable uses, or it may not. in this case, *pinum and inum are the same variable. When I say "produces", it's important to note than no constructors are called. This is why you MUST initialize pointers before using them: Pointer dereferencing will NEVER allocate storage.
returnSame(*pinum)
This function takes a reference and returns the same reference. It's helpful to realize that this function could be written with pointers as well, and behave exactly the same way. References do not perform any initialization either, in that they do not call constructors. However, it is illegal to have an uninitialized reference, so running into uninitialized memory through them is not as common a mistake as with pointers. Your function could be rewritten to use pointers in the following way:
int* returnSamePointer( int *example ) { return example; }
In this case, you would not need to dereference the pointer before passing it, but you would need to dereference the function's return value before printing it:
std::cout << "inum: " << *(returnSamePointer(pinum)) << std::endl;
NULL References
Declaring a NULL reference is dangerous, since attempting to use it will automatically attempt to dereference it, which will cause a segmentation fault. You can, however, safely check if a reference is a null reference. Again, I highly recommend not using these ever.
int& nullRef = *((int *) NULL); // creates a reference to nothing
bool isRefNull = (&nullRef == NULL); // true
Summary
Pointer and Reference types are two different ways to accomplish the same thing
Most of the gotchas that apply to one apply to the other
Neither pointers nor references will call constructors or destructors for referenced values implicitly under any circumstances
Declaring a reference to a dereferenced pointer is perfectly legal, as long as the pointer is initialized properly
A compiler doesn't "call" anything. It just generates code. Dereferencing a pointer would at the most basic level correspond to some sort of load instruction, but in the present code the compiler can easily optimize this away and just print the value directly, or perhaps shortcut directly to loading inum.
Concerning your "temporary object": Dereferencing a pointer always gives an lvalue.
Perhaps there's a more interesting question hidden in your question, though: How does the compiler implement passing function arguments as references?
Sorry for turning to here for such a basic question, but can someone just quickly clear this up for me? I'll then delete the thread so as not to cause noob clutter.
In the following example from the C++ Primer Plus text, doesn't the & operator in the function declaration designate that the function returns a pointer to a Stock object? Why then does the function proceed to return the s and this objects by value instead?
"...What you want to return, however, is not this, because this is the address of the object. You want to return the object itself, and that is symbolized by *this. (Recall that applying the dereferencing operator * to a pointer yields the value to which the pointer points.) Now you can complete the method definition by using *this as an alias for the invoking object."
const Stock & Stock::topval(const Stock & s) const {
if (s.total_val > total_val)
return s; // argument object
else
return *this; // invoking object
}
Yeah, that's confusing. C++ massively overloads every symbol, because there just aren't enough symbols on the keyboard.
The ampersand & is used for two different meanings which are conceptually similar, but are actually completely different language features.
Meaning 1: Reference type declaration. Append an ampersand to type A which means a-reference-to-type-A. Example:
Stock x;
Stock& s = x; // now s is a reference to x
Meaning 2: Address-of operator. A unary operator that returns a pointer to its argument. Example:
Stock x;
Stock* s = &x; // now s a pointer to x
Reminder: References and pointers are exactly the same thing, except they have different syntax, and references can never be null, and you can't have a reference to a reference.
Don't delete this thread, we love n00bs. I'm a n00b myself.
const Stock & means return a const reference to an object. A pointer to an object would be const Stock *. Don't mix the two! So the this pointer is being dereferenced and returned.
I'm new to the C++ community, and just have a quick question about how C++ passes variables by reference to functions.
When you want to pass a variable by reference in C++, you add an & to whatever argument you want to pass by reference. How come when you assign a value to a variable that is being passed by reference why do you say variable = value; instead of saying *variable = value?
void add_five_to_variable(int &value) {
// If passing by reference uses pointers,
// then why wouldn't you say *value += 5?
// Or does C++ do some behind the scene stuff here?
value += 5;
}
int main() {
int i = 1;
add_five_to_variable(i);
cout << i << endl; // i = 6
return 0;
}
If C++ is using pointers to do this with behind the scenes magic, why aren't dereferences needed like with pointers? Any insight would be much appreciated.
When you write,
int *p = ...;
*p = 3;
That is syntax for assigning 3 to the object referred to by the pointer p. When you write,
int &r = ...;
r = 3;
That is syntax for assigning 3 to the object referred to by the reference r. The syntax and the implementation are different. References are implemented using pointers (except when they're optimized out), but the syntax is different.
So you could say that the dereferencing happens automatically, when needed.
C++ uses pointers behind the scenes but hides all that complication from you. Passing by reference also enables you to avoid all the problems asssoicated with invalid pointers.
When you pass an object to a function by reference, you manipulate the object directly in the function, without referring to its address like with pointers. Thus, when manipulating this variable, you don't want to dereference it with the *variable syntax. This is good practice to pass objects by reference because:
A reference can't be redefined to point to another object
It can't be null. you have to pass a valid object of that type to the function
How the compiler achieves the "pass by reference" is not really relevant in your case.
The article in Wikipedia is a good ressource.
There are two questions in one, it seems:
one question is about syntax: the difference between pointer and reference
the other is about mechanics and implementation: the in-memory representation of a reference
Let's address the two separately.
Syntax of references and pointers
A pointer is, conceptually, a "sign" (as road sign) toward an object. It allows 2 kind of actions:
actions on the pointee (or object pointed to)
actions on the pointer itself
The operator* and operator-> allow you to access the pointee, to differenciate it from your accesses to the pointer itself.
A reference is not a "sign", it's an alias. For the duration of its life, come hell or high water, it will point to the same object, nothing you can do about it. Therefore, since you cannot access the reference itself, there is no point it bothering you with weird syntax * or ->. Ironically, not using weird syntax is called syntactic sugar.
Mechanics of a reference
The C++ Standard is silent on the implementation of references, it merely hints that if the compiler can it is allowed to remove them. For example, in the following case:
int main() {
int a = 0;
int& b = a;
b = 1;
return b;
}
A good compiler will realize that b is just a proxy for a, no room for doubts, and thus simply directly access a and optimize b out.
As you guessed, a likely representation of a reference is (under the hood) a pointer, but do not let it bother you, it does not affect the syntax or semantics. It does mean however that a number of woes of pointers (like access to objects that have been deleted for example) also affect references.
The explicit dereference is not required by design - that's for convenience. When you use . on a reference the compiler emits code necessary to access the real object - this will often include dereferencing a pointer, but that's done without requiring an explicit dereference in your code.