Given the following c++ function:
int& ReturnAReference() {
/* Do something here */
}
Is there any difference between the two statements:
int normalVariable = ReturnAReference();
int& referenceVariable = ReturnAReferene();
Is one version preferred over the other?
Regarding this:
int normalVariable = ReturnAReference();
normalVariable is an integer, and is assigned the value of the int that ReturnAReference() references. As such incrementing, assigning, or doing anything else to normalVariable will not affect whatever ReturnAReference() has internally.
Regarding this:
int& referenceVariable = ReturnAReference();
referenceVariable is a reference to an integer that would otherwise be internal to ReturnAReference(). As such incrementing, assigning, or doing anything else to referenceVariable will affect whatever ReturnAReference() has internally.
What is preferred depends on what you're trying to accomplish, but in many cases the second approach (using referenceVariable) violates "encapsulation" ( http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming) ), which is considered poor design.
EDIT: And I should add that if ReturnAReference() is returning a reference to a variable that is local in that function, that reference will be invalid as soon as ReturnAReference() returns.
After a reference has been initialized, e.g. via
int i = 42;
int& r1 = i;
int& r2 = ReturnAReference();
int& r3(i);
int& r4{i}; // C++11
int& r5 = {i}; // C++11
it becomes an alias, i.e. another name, of the object it has been initialized with. It is not another integer. Note that in the language of the C++ Standard, an object is simply a region of storage, not necessarily an instance of a class.
As a reference is an alias, if you operate with the reference, you'll operate on the original object (the one it has been initialized with):
int i = 42;
int& r = i;
// r is now an alias for i, both refer to the same object
r = 21; // a true assignment
std::cout << i; // will print 21
The statement
int normalVariable = ReturnAReference();
introduces a new object of type int and a name for that object: normalVariable. This object is initialized with the object returned by ReturnAReference(), which means that the value of the returned object is copied into the new object called normalVariable.
On the other hand, the statement
int& referenceVariable = ReturnAReferene();
only introduces a new name for the object returned by ReturnAReference().
If your function would return a non-reference int, like int ReturnAnInt();, the statement
int& r = ReturnAnInt();
would become illegal, as the object returned by this function is a temporary, which only lives until the end of this line (in this case). In the next line, the name r would refer to an object that does not exist any more, so it has been made illegal to bind non-const references to temporary objects.
Let's suppose you have the following definitions :
int test = 4;
int& ReturnAReference() {
return test;
}
1) Is there any difference between the two statements:
int normalVariable = ReturnAReference();
In this case, normalVariable will hold a copy of the return value (not a reference), because the assignment operator copies the value referred by the return value into normalVariable. This means that after
normalVariable = 1;
normalVariable will now be 1, but test will still be 4.
However, if you were to have written
int& referenceVariable = ReturnAReferene();
and do
normalVariable = 1;
normalVariable would now be 1 and test would also be 1, since normalVariable is only an alias for test.
Be careful though when you return a reference. For instance, if you were to do
int& ReturnAReference() {
int i = 0;
return i;
}
the reference returned from ReturnAReference() would not be valid anymore, since it is only valid inside the function and will be destroyed when it is exited.
2) Is one version preferred over the other?
In the case of ints or other primitive types, I would prefer the int return value over int&, simply because an int is small and won't be expensive to copy (it will nearly always fit in a register). Also, the int& return value entails safety issues if the reference refers to a local variable. For classes or structs, it always depends, but you have to be careful when returning local variables by reference or by pointer.
If you want to modify the variable returned by reference from the function, or to keep track of any changes to its value, use int&. It's up to you to make sure the variable you are referencing will exist for as long as you access it. If you just care about the value of the variable returned by reference at that point, use int.
FYI, std::vector's operator [] and at functions return by reference allowing syntax such as the following v.at(0) = 2.
Related
I have the following code:
int main() {
int x = 3;
int &ref = x;
int &ref2 = ref;
ref = 100;
std::cout <<ref;
std::cout <<ref2;
return 0;
}
This print out 100 and 100. I find it confusing. My understanding was that both ref and ref2 are references to the underlying object (x=3). We then change the value of ref.
As such, I expected 100 and 3.
You don't ever change the value of ref (the language does not let you rebind a reference). In fact, this is why you need to use reference initialisation when you create a reference: you can't write int &ref; ref = x; for example.
The statement ref = 100; changes the value of the object to which the reference is bound.
Hence the output of x, ref, and ref2 are identical.
My understanding was that both ref and ref2 are references to the underlying object (x=3)
Yes.
Well, they're both references to x, whose initial value is 3.
Essentially you have a single integer object, which you can refer to by the names any of the names x, ref or ref2.
We then change the value of ref
No, you're contradicting yourself.
Objects have values. References like ref are not objects, but references to objects, and they don't have a value of their own to change.
You said that ref is a reference, which is true - it is a reference to an object of type int, which can take a value, and whose value is changed when you write ref = 100. The names x, ref and ref2 still refer to the same integer object afterwards, but now its value is 100 instead of 3.
You cannot reseat a reference (make it refer to a different object), and a reference does not have a value to change. It refers to an object, whose value may be changed via the reference.
NB. I don't think this question is quite a duplicate of Can we reassign the reference, even though it contains some of the same misunderstanding.
Why these definitions are all ok:
int func(int p=255) {
return p;
}
int func1(const int &p=255) {
return p;
}
but this definition:
int func2(int &p=255) {
return p;
}
leads to compile error ?
What is the logic behind it ?
Taking arguments by reference means, you dont work with your local copy of the variable, but with a variable already defined in the scope of the calling function.
While your first example makes sense (you have a local variable p that you can fill with a default value) the second example is a bit more tricky: Usually when using references you expect the variable to have an address, since you want to modify it. For const-refernces, the compiler will still allow you to pass a literal, even if something like "reference to a literal" makes no sense at all.
In the third case the compiler expects you to modify p. But what part of the memory should this modification affect? "255" has no address - therefore it cant be used as a reference.
If you want to have a more detailed explanation, you should probably look for keywords like "rvalue" and "lvalue".
The attempted function definition
auto func2( int& p = 255 )
-> int
{ return p; }
… fails because you can't bind an rvalue to a reference to non-const. Basically that rule is because a simple value like 255 isn't modifiable. While the reference can be used to modify.
One simple solution is to express the default as a separate overload:
auto func2( int& p )
-> int
{ return p; }
auto func2()
-> int
{
int scratchpad = 255;
return func2( scratchpad );
}
A non-const reference must be bound to lvalue (i.e. its address could be got). 255 (i.e. an int literal) is not a lvalue, so int &p=255 fails.
A const reference could be bound to rvalue, and for this case, a temporary int will be created and initialized from 255. The temporary int's lifetime will be the same as the const reference.
int func(int p=255) {
return p;
}
p here is copied by value, and it is defined to exist in the scope of func.
int func2(int &p) {
return p;
}
// e.g. use:
int value = 10;
func2(value); // func2 *could* modify value because it is passed by non-const reference
In this case the compiler here expects p to have a name somewhere in memory (i.e. lvalue), so it can possibly write to it within func2. Passing by non-const reference allows you to modify the variable used in the function call. Since p must belong to someone else somewhere since it can be modified, you can't assign a default value to it.
But what about the const-reference case? Here, the compiler is smart enough to know that p can never be written to since it is const, so it doesn't need to have a name in memory to write to. In cases of a literal being passed (e.g. 255), it (behind the scenes) essentially creates a temporary and passes that temporary variable to the function.
int func1(const int &p=255) {
return p;
}
func1(10);
// Behind the scenes, the compiler creates something along these lines
// since it can never be modified.
const int some_temporary = 10;
func1(some_temporary);
consider the below code
int& func1() {
int x = 2;
return x;
}
int& func2(int &x) {
return x;
}
int main() {
int x = func1();
cout<<"\n : "<<x;
int y = 3;
x = func2(y);
cout<<"\n : "<<x<<"\n";
}
output:
: 2
: 3
The code is working absolutely fine , but I have few doubts that I have listed below:
In func1() I have returned a non_reference variable "x" but the
return type is reference to an int, so how is the conversion
happening and what part of "x" function is actually returning.
In func1() "x" is returned as reference but being a stack variable how the reference
of x can be returned , I mean it will have no significance after the completion ( I
am relating this point to the logic " Functions should not return the pointers whose
memory is allocated in statically").
In func1() it is returning a non refrence variable "x" as refrence
to an int and in func2() it is returning a refernce variable "x" as
refrence to an int. As both "x" are of different type but why
return type is same..
I am confused because I am trying t relate C++ with c as in that everything is clear but here majorily due to lack of memory layout description of refrence variable, so if some could tell about that also then it will be very helpful to me
In func1, what you are returning is a reference to something. This something is x, which is local to func1, whose lifetime ends upon returning. Then, in main, you assign the contents of the referred-to variable (x of func1, which is eating dandelions by the roots) to initialize main's local variable x. This is undefined behaviour, which means that the program is allowed to interpret this as anything it wants, formatting your hard drive or anything. (most probably, func1 returned the pointer to the variable of the called stack frame, which probably still contains the right value, because why bother erasing the values on the stack when they will be crushed by the next function call anyway?) Anyway, would the program be compiled with other optimization options, it may give another answer.
In func2, what you are returning is a reference to something. This something is what is referred-to by x, which refers to main's y. Then, you assign to main's x the value of the referred-to variable, which is y.
With regards to your question of the memory layout of references, in C, pointers are addresses in memory. Period. No escape. In C++, references are a higher-level mechanism where you "refer to something", "talk about something", "look it's me right there". They are perfectly implementable as plain pointers. But as a language concept, they are a bit more amenable to be optimized away, because they are immutable. (Once a reference is set, it cannot be changed. And it refers to something -- even an object at an invalid memory location) That's why the Standard does not specify storage for references. For freedom of optimization.
UPDATE: With regards to your first doubt, main's x is a full-fledged variable (it is declared as such) and not a reference. So assigning it any other value will not change y's value. In C++, when you evaluate a reference in an expression, like so:
int x = 0;
int& y = x;
// Right hand side is the evaluation of the reference y
int z = y;
It gets evaluated to the value of the referred-to variable, i.e. the value of x, i.e. 0. And z is a variable that is distinct from x.
With regards to your third doubt, func2 will return a reference. When a function is declared as returning a reference, what it returns is a reference. A reference is something that says "I'm this other one over there". In the case of the return value, at assembler level, provided that the function is not inlined and the call really happens, and so on, what will most probably be returned by func1 or func2 will be a pointer to the referred to-variable. Actually, in C++, a reference to an int is the type of what you get by defererencing an int pointer with *. Compare the previous example code with the same code with pointers.
int x = 0;
int* const y = &x;
int z = *y;
With references, the & and * occur silently.
Just so you know, references have been introduced into the language to support operator overloading, especially the assignment operator.
// Quizz : what is the type of (b = A(123))? What if it is a 1MB object?
// What should be the type of the right-hand side of the assignment operator?
A a, b;
a = b = A(123);
It can't be a value or it would be performing horrendously bad (passing result by copy). It has to be some kind of pointer, but it can't be. There would be &s or *s somewhere, depending on how you word the Standand for the functionality. Instead of inventing lots of special typesystem cases of operator overloading, Stroustrup decided to provide two orthogonal functionality: references, which are syntax-fussless immutable pointers (and the type of "talking about a variable"), and operator overloading which is cleanly enabled by references.
A reference is a way to make two names alias the same memory.
Take this function for example:
void something_cpp(int &x)
{
x = 2;
}
You can think of this in C terms as the following:
void something_c(int *x)
{
*x = 2;
}
similarly a function returning a reference in c++:
int something[10];
int &something2_cpp(void)
{
return something[0];
}
int main(int argc, char *argv[])
{
something2_cpp() = 10;
}
Can be thought of like this in C:
int something[10];
int *something2_c(void)
{
return &something[0];
}
int main(int argc, char *argv[])
{
*something2_c() = 10;
}
I need to clear a basic concept. This code works fine. Can somebody explain me that if the function calDouble already returning the address (reference) of int why I need to use & operator further in main int *j = &calDouble(i); to get the address (reference) of int? Thanks.
int& calDouble(int x)
{
x = x*2;
return x;
}
int main(int argc, char *argv[])
{
int i = 99;
int *j = &calDouble(i);
system("PAUSE");
return EXIT_SUCCESS;
}
int& calDouble(int x) doesn't return an address, but a reference to an int.
You need to take the address of the reference to be able to assign it to a pointer.
Note however that your code invokes undefined behavior. Because you pass the parameter by value, a copy of it is created inside the function. So you return a local variable by reference, which is not legal.
I think your confusion comes from &. This can be used in two ways:
applied to a variable &x, it takes its address
when in a declaration int& x, it defines a reference
A reference is just an alias, a different name for a variable.
int x = 0;
int& y = x;
Now, x and y refer to the same variable.
int* z = &x;
takes the address of x.
int& is a reference type. It is not the address.
To see what &calDouble(i) does, consider if we had broken it into two statements:
int& x = calDouble(i);
... = &x;
The calDouble() function returns a reference type, and the prepended & then takes the address-of whatever was returned. So the type is now int*, which is why that line compiles.
However, your program exhibits undefined behavior! The x in calDouble() goes away once the function ends. The value that was originally there may still be in memory, which is why your program "works". But this is not reliable in production code, and one day your perfectly working test program may blow-up the moment it's deployed.
It's generally a bad idea to return a reference to a local variable for this vary reason. (You'll see class methods return references to member data, which is fine as long as the object is still in scope since those variables will still exist.) Just return a regular int and get on with life. An optimizing compiler can do some return value optimization if you're really worried about performance when returning large objects.
As I read
---references are not pointers it is the object itself,A reference is an entity that is an alias for another object.
---references can never represent NULL
---Reference variables allow two variable names to address the same memory location:
---it cannot later be made to refer to a different object
---A reference is not a variable as a variable is only introduced by the declaration of an object. An object is a region of storage and, in C++, references do not (necessarily) take up any storage.
now does the below line converts the variable integers to a constant integers
const Array& ref = integers
furthermore I read this
also which says that you can change the state of a referent.
Please suggest/clarify.
No, it does not convert integers. You now just have an alias for integers through which you can't change it. You can still change integers through the original name:
int i = 0;
int const& i_ref = i;
i = 5;
cout << i_ref; // outputs 5
The above examble also shows how you can change the state of the referee.
You cannot change the state of a const reference. Apart from that everything you mentioned in there is true.
So for example:
const int& ref = integers;
ref = 5;
will fail to compile. Where as
int& ref = integers;
ref = 5;
will compile and it will change the value stored in integers to 5.
Furthermore a const reference means that you cannot change value of the object it refers using the reference. You can still modify it using the original variable name. For example:
const int& ref = integers;
integers = 5;
std::cout<<ref<<", "<<integers<<std::endl;
is completely valid and will produce:
5, 5