Related
I am trying to understand how to use reference parameters. There are several examples in my text, however they are too complicated for me to understand why and how to use them.
How and why would you want to use a reference? What would happen if you didn't make the parameter a reference, but instead left the & off?
For example, what's the difference between these functions:
int doSomething(int& a, int& b);
int doSomething(int a, int b);
I understand that reference variables are used in order to change a formal->reference, which then allows a two-way exchange of parameters. However, that is the extent of my knowledge, and a more concrete example would be of much help.
Think of a reference as an alias. When you invoke something on a reference, you're really invoking it on the object to which the reference refers.
int i;
int& j = i; // j is an alias to i
j = 5; // same as i = 5
When it comes to functions, consider:
void foo(int i)
{
i = 5;
}
Above, int i is a value and the argument passed is passed by value. That means if we say:
int x = 2;
foo(x);
i will be a copy of x. Thus setting i to 5 has no effect on x, because it's the copy of x being changed. However, if we make i a reference:
void foo(int& i) // i is an alias for a variable
{
i = 5;
}
Then saying foo(x) no longer makes a copy of x; i is x. So if we say foo(x), inside the function i = 5; is exactly the same as x = 5;, and x changes.
Hopefully that clarifies a bit.
Why is this important? When you program, you never want to copy and paste code. You want to make a function that does one task and it does it well. Whenever that task needs to be performed, you use that function.
So let's say we want to swap two variables. That looks something like this:
int x, y;
// swap:
int temp = x; // store the value of x
x = y; // make x equal to y
y = temp; // make y equal to the old value of x
Okay, great. We want to make this a function, because: swap(x, y); is much easier to read. So, let's try this:
void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
This won't work! The problem is that this is swapping copies of two variables. That is:
int a, b;
swap(a, b); // hm, x and y are copies of a and b...a and b remain unchanged
In C, where references do not exist, the solution was to pass the address of these variables; that is, use pointers*:
void swap(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int a, b;
swap(&a, &b);
This works well. However, it's a bit clumsy to use, and actually a bit unsafe. swap(nullptr, nullptr), swaps two nothings and dereferences null pointers...undefined behavior! Fixable with some checks:
void swap(int* x, int* y)
{
if (x == nullptr || y == nullptr)
return; // one is null; this is a meaningless operation
int temp = *x;
*x = *y;
*y = temp;
}
But looks how clumsy our code has gotten. C++ introduces references to solve this problem. If we can just alias a variable, we get the code we were looking for:
void swap(int& x, int& y)
{
int temp = x;
x = y;
y = temp;
}
int a, b;
swap(a, b); // inside, x and y are really a and b
Both easy to use, and safe. (We can't accidentally pass in a null, there are no null references.) This works because the swap happening inside the function is really happening on the variables being aliased outside the function.
(Note, never write a swap function. :) One already exists in the header <algorithm>, and it's templated to work with any type.)
Another use is to remove that copy that happens when you call a function. Consider we have a data type that's very big. Copying this object takes a lot of time, and we'd like to avoid that:
struct big_data
{ char data[9999999]; }; // big!
void do_something(big_data data);
big_data d;
do_something(d); // ouch, making a copy of all that data :<
However, all we really need is an alias to the variable, so let's indicate that. (Again, back in C we'd pass the address of our big data type, solving the copying problem but introducing clumsiness.):
void do_something(big_data& data);
big_data d;
do_something(d); // no copies at all! data aliases d within the function
This is why you'll hear it said you should pass things by reference all the time, unless they are primitive types. (Because internally passing an alias is probably done with a pointer, like in C. For small objects it's just faster to make the copy then worry about pointers.)
Keep in mind you should be const-correct. This means if your function doesn't modify the parameter, mark it as const. If do_something above only looked at but didn't change data, we'd mark it as const:
void do_something(const big_data& data); // alias a big_data, and don't change it
We avoid the copy and we say "hey, we won't be modifying this." This has other side effects (with things like temporary variables), but you shouldn't worry about that now.
In contrast, our swap function cannot be const, because we are indeed modifying the aliases.
Hope this clarifies some more.
*Rough pointers tutorial:
A pointer is a variable that holds the address of another variable. For example:
int i; // normal int
int* p; // points to an integer (is not an integer!)
p = &i; // &i means "address of i". p is pointing to i
*p = 2; // *p means "dereference p". that is, this goes to the int
// pointed to by p (i), and sets it to 2.
So, if you've seen the pointer-version swap function, we pass the address of the variables we want to swap, and then we do the swap, dereferencing to get and set values.
Lets take a simple example of a function named increment which increments its argument. Consider:
void increment(int input) {
input++;
}
which will not work as the change takes place on the copy of the argument passed to the function on the actual parameter. So
int i = 1;
std::cout<<i<<" ";
increment(i);
std::cout<<i<<" ";
will produce 1 1 as output.
To make the function work on the actual parameter passed we pass its reference to the function as:
void increment(int &input) { // note the &
input++;
}
the change made to input inside the function is actually being made to the actual parameter. This will produce the expected output of 1 2
GMan's answer gives you the lowdown on references. I just wanted to show you a very basic function that must use references: swap, which swaps two variables. Here it is for ints (as you requested):
// changes to a & b hold when the function exits
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
// changes to a & b are local to swap_noref and will go away when the function exits
void swap_noref(int a, int b) {
int tmp = a;
a = b;
b = tmp;
}
// changes swap_ptr makes to the variables pointed to by pa & pb
// are visible outside swap_ptr, but changes to pa and pb won't be visible
void swap_ptr(int *pa, int *pb) {
int tmp = *pa;
*pa = *pb;
*pb = tmp;
}
int main() {
int x = 17;
int y = 42;
// next line will print "x: 17; y: 42"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap can alter x & y
swap(x,y);
// next line will print "x: 42; y: 17"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap_noref can't alter x or y
swap_noref(x,y);
// next line will print "x: 42; y: 17"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap_ptr can alter x & y
swap_ptr(&x,&y);
// next line will print "x: 17; y: 42"
std::cout << "x: " << x << "; y: " << y << std::endl
}
There is a cleverer swap implementation for ints that doesn't need a temporary. However, here I care more about clear than clever.
Without references (or pointers), swap_noref cannot alter the variables passed to it, which means it simply cannot work. swap_ptr can alter variables, but it uses pointers, which are messy (when references won't quite cut it, however, pointers can do the job). swap is the simplest overall.
On Pointers
Pointers let you do some of the same things as references. However, pointers put more responsibility on the programmer to manage them and the memory they point to (a topic called "memory management"–but don't worry about it for now). As a consequence, references should be your preferred tool for now.
Think of variables as names bound to boxes that store a value. Constants are names bound directly to values. Both map names to values, but the value of constants can't be changed. While the value held in a box can change, the binding of name to box can't, which is why a reference cannot be changed to refer to a different variable.
Two basic operations on variables are getting the current value (done simply by using the variable's name) and assigning a new value (the assignment operator, '='). Values are stored in memory (the box holding a value is simply a contiguous region of memory). For example,
int a = 17;
results in something like (note: in the following, "foo # 0xDEADBEEF" stands for a variable with name "foo" stored at address "0xDEADBEEF". Memory addresses have been made up):
____
a # 0x1000: | 17 |
----
Everything stored in memory has a starting address, so there's one more operation: get the address of the value ("&" is the address-of operator). A pointer is a variable that stores an address.
int *pa = &a;
results in:
______ ____
pa # 0x10A0: |0x1000| ------> # 0x1000: | 17 |
------ ----
Note that a pointer simply stores a memory address, so it doesn't have access to the name of what it points to. In fact, pointers can point to things without names, but that's a topic for another day.
There are a few operations on pointers. You can dereference a pointer (the "*" operator), which gives you the data the pointer points to. Dereferencing is the opposite of getting the address: *&a is the same box as a, &*pa is the same value as pa, and *pa is the same box as a. In particular, pa in the example holds 0x1000; * pa means "the int in memory at location pa", or "the int in memory at location 0x1000". "a" is also "the int at memory location 0x1000". Other operation on pointers are addition and subtraction, but that's also a topic for another day.
// Passes in mutable references of a and b.
int doSomething(int& a, int& b) {
a = 5;
cout << "1: " << a << b; // prints 1: 5,6
}
a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b; // prints 2: 5,6
Alternatively,
// Passes in copied values of a and b.
int doSomething(int a, int b) {
a = 5;
cout << "1: " << a << b; // prints 1: 5,6
}
a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b; // prints 2: 0,6
Or the const version:
// Passes in const references a and b.
int doSomething(const int &a, const int &b) {
a = 5; // COMPILE ERROR, cannot assign to const reference.
cout << "1: " << b; // prints 1: 6
}
a = 0;
b = 6;
doSomething(a, b);
References are used to pass locations of variables, so they don't need to be copied on the stack to the new function.
A simple pair of examples which you can run online.
The first uses a normal function, and the second uses references:
Example 1 (no reference)
Example 2 (reference)
Edit - here's the source code incase you don't like links:
Example 1
using namespace std;
void foo(int y){
y=2;
}
int main(){
int x=1;
foo(x);
cout<<x;//outputs 1
}
Example 2
using namespace std;
void foo(int & y){
y=2;
}
int main(){
int x=1;
foo(x);
cout<<x;//outputs 2
}
I don't know if this is the most basic, but here goes...
typedef int Element;
typedef std::list<Element> ElementList;
// Defined elsewhere.
bool CanReadElement(void);
Element ReadSingleElement(void);
int ReadElementsIntoList(int count, ElementList& elems)
{
int elemsRead = 0;
while(elemsRead < count && CanReadElement())
elems.push_back(ReadSingleElement());
return count;
}
Here we use a reference to pass our list of elements into ReadElementsIntoList(). This way, the function loads the elements right into the list. If we didn't use a reference, then elems would be a copy of the passed-in list, which would have the elements added to it, but then elems would be discarded when the function returns.
This works both ways. In the case of count, we don't make it a reference, because we don't want to modify the count passed in, instead returning the number of elements read. This allows the calling code to compare the number of elements actually read to the requested number; if they don't match, then CanReadElement() must have returned false, and immediately trying to read some more would likely fail. If they match, then maybe count was less than the number of elements available, and a further read would be appropriate. Finally, if ReadElementsIntoList() needed to modify count internally, it could do so without mucking up the caller.
How about by metaphor: Say your function counts beans in a jar. It needs the jar of beans and you need to know the result which can't be the return value (for any number of reasons). You could send it the jar and the variable value, but you'll never know if or what it changes the value to. Instead, you need to send it that variable via a return addressed envelope, so it can put the value in that and know it's written the result to the value at said address.
Correct me if I'm wrong, but a reference is only a dereferenced pointer, or?
The difference to a pointer is, that you can't easily commit a NULL.
I am trying to understand how to use reference parameters. There are several examples in my text, however they are too complicated for me to understand why and how to use them.
How and why would you want to use a reference? What would happen if you didn't make the parameter a reference, but instead left the & off?
For example, what's the difference between these functions:
int doSomething(int& a, int& b);
int doSomething(int a, int b);
I understand that reference variables are used in order to change a formal->reference, which then allows a two-way exchange of parameters. However, that is the extent of my knowledge, and a more concrete example would be of much help.
Think of a reference as an alias. When you invoke something on a reference, you're really invoking it on the object to which the reference refers.
int i;
int& j = i; // j is an alias to i
j = 5; // same as i = 5
When it comes to functions, consider:
void foo(int i)
{
i = 5;
}
Above, int i is a value and the argument passed is passed by value. That means if we say:
int x = 2;
foo(x);
i will be a copy of x. Thus setting i to 5 has no effect on x, because it's the copy of x being changed. However, if we make i a reference:
void foo(int& i) // i is an alias for a variable
{
i = 5;
}
Then saying foo(x) no longer makes a copy of x; i is x. So if we say foo(x), inside the function i = 5; is exactly the same as x = 5;, and x changes.
Hopefully that clarifies a bit.
Why is this important? When you program, you never want to copy and paste code. You want to make a function that does one task and it does it well. Whenever that task needs to be performed, you use that function.
So let's say we want to swap two variables. That looks something like this:
int x, y;
// swap:
int temp = x; // store the value of x
x = y; // make x equal to y
y = temp; // make y equal to the old value of x
Okay, great. We want to make this a function, because: swap(x, y); is much easier to read. So, let's try this:
void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
This won't work! The problem is that this is swapping copies of two variables. That is:
int a, b;
swap(a, b); // hm, x and y are copies of a and b...a and b remain unchanged
In C, where references do not exist, the solution was to pass the address of these variables; that is, use pointers*:
void swap(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int a, b;
swap(&a, &b);
This works well. However, it's a bit clumsy to use, and actually a bit unsafe. swap(nullptr, nullptr), swaps two nothings and dereferences null pointers...undefined behavior! Fixable with some checks:
void swap(int* x, int* y)
{
if (x == nullptr || y == nullptr)
return; // one is null; this is a meaningless operation
int temp = *x;
*x = *y;
*y = temp;
}
But looks how clumsy our code has gotten. C++ introduces references to solve this problem. If we can just alias a variable, we get the code we were looking for:
void swap(int& x, int& y)
{
int temp = x;
x = y;
y = temp;
}
int a, b;
swap(a, b); // inside, x and y are really a and b
Both easy to use, and safe. (We can't accidentally pass in a null, there are no null references.) This works because the swap happening inside the function is really happening on the variables being aliased outside the function.
(Note, never write a swap function. :) One already exists in the header <algorithm>, and it's templated to work with any type.)
Another use is to remove that copy that happens when you call a function. Consider we have a data type that's very big. Copying this object takes a lot of time, and we'd like to avoid that:
struct big_data
{ char data[9999999]; }; // big!
void do_something(big_data data);
big_data d;
do_something(d); // ouch, making a copy of all that data :<
However, all we really need is an alias to the variable, so let's indicate that. (Again, back in C we'd pass the address of our big data type, solving the copying problem but introducing clumsiness.):
void do_something(big_data& data);
big_data d;
do_something(d); // no copies at all! data aliases d within the function
This is why you'll hear it said you should pass things by reference all the time, unless they are primitive types. (Because internally passing an alias is probably done with a pointer, like in C. For small objects it's just faster to make the copy then worry about pointers.)
Keep in mind you should be const-correct. This means if your function doesn't modify the parameter, mark it as const. If do_something above only looked at but didn't change data, we'd mark it as const:
void do_something(const big_data& data); // alias a big_data, and don't change it
We avoid the copy and we say "hey, we won't be modifying this." This has other side effects (with things like temporary variables), but you shouldn't worry about that now.
In contrast, our swap function cannot be const, because we are indeed modifying the aliases.
Hope this clarifies some more.
*Rough pointers tutorial:
A pointer is a variable that holds the address of another variable. For example:
int i; // normal int
int* p; // points to an integer (is not an integer!)
p = &i; // &i means "address of i". p is pointing to i
*p = 2; // *p means "dereference p". that is, this goes to the int
// pointed to by p (i), and sets it to 2.
So, if you've seen the pointer-version swap function, we pass the address of the variables we want to swap, and then we do the swap, dereferencing to get and set values.
Lets take a simple example of a function named increment which increments its argument. Consider:
void increment(int input) {
input++;
}
which will not work as the change takes place on the copy of the argument passed to the function on the actual parameter. So
int i = 1;
std::cout<<i<<" ";
increment(i);
std::cout<<i<<" ";
will produce 1 1 as output.
To make the function work on the actual parameter passed we pass its reference to the function as:
void increment(int &input) { // note the &
input++;
}
the change made to input inside the function is actually being made to the actual parameter. This will produce the expected output of 1 2
GMan's answer gives you the lowdown on references. I just wanted to show you a very basic function that must use references: swap, which swaps two variables. Here it is for ints (as you requested):
// changes to a & b hold when the function exits
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
// changes to a & b are local to swap_noref and will go away when the function exits
void swap_noref(int a, int b) {
int tmp = a;
a = b;
b = tmp;
}
// changes swap_ptr makes to the variables pointed to by pa & pb
// are visible outside swap_ptr, but changes to pa and pb won't be visible
void swap_ptr(int *pa, int *pb) {
int tmp = *pa;
*pa = *pb;
*pb = tmp;
}
int main() {
int x = 17;
int y = 42;
// next line will print "x: 17; y: 42"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap can alter x & y
swap(x,y);
// next line will print "x: 42; y: 17"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap_noref can't alter x or y
swap_noref(x,y);
// next line will print "x: 42; y: 17"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap_ptr can alter x & y
swap_ptr(&x,&y);
// next line will print "x: 17; y: 42"
std::cout << "x: " << x << "; y: " << y << std::endl
}
There is a cleverer swap implementation for ints that doesn't need a temporary. However, here I care more about clear than clever.
Without references (or pointers), swap_noref cannot alter the variables passed to it, which means it simply cannot work. swap_ptr can alter variables, but it uses pointers, which are messy (when references won't quite cut it, however, pointers can do the job). swap is the simplest overall.
On Pointers
Pointers let you do some of the same things as references. However, pointers put more responsibility on the programmer to manage them and the memory they point to (a topic called "memory management"–but don't worry about it for now). As a consequence, references should be your preferred tool for now.
Think of variables as names bound to boxes that store a value. Constants are names bound directly to values. Both map names to values, but the value of constants can't be changed. While the value held in a box can change, the binding of name to box can't, which is why a reference cannot be changed to refer to a different variable.
Two basic operations on variables are getting the current value (done simply by using the variable's name) and assigning a new value (the assignment operator, '='). Values are stored in memory (the box holding a value is simply a contiguous region of memory). For example,
int a = 17;
results in something like (note: in the following, "foo # 0xDEADBEEF" stands for a variable with name "foo" stored at address "0xDEADBEEF". Memory addresses have been made up):
____
a # 0x1000: | 17 |
----
Everything stored in memory has a starting address, so there's one more operation: get the address of the value ("&" is the address-of operator). A pointer is a variable that stores an address.
int *pa = &a;
results in:
______ ____
pa # 0x10A0: |0x1000| ------> # 0x1000: | 17 |
------ ----
Note that a pointer simply stores a memory address, so it doesn't have access to the name of what it points to. In fact, pointers can point to things without names, but that's a topic for another day.
There are a few operations on pointers. You can dereference a pointer (the "*" operator), which gives you the data the pointer points to. Dereferencing is the opposite of getting the address: *&a is the same box as a, &*pa is the same value as pa, and *pa is the same box as a. In particular, pa in the example holds 0x1000; * pa means "the int in memory at location pa", or "the int in memory at location 0x1000". "a" is also "the int at memory location 0x1000". Other operation on pointers are addition and subtraction, but that's also a topic for another day.
// Passes in mutable references of a and b.
int doSomething(int& a, int& b) {
a = 5;
cout << "1: " << a << b; // prints 1: 5,6
}
a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b; // prints 2: 5,6
Alternatively,
// Passes in copied values of a and b.
int doSomething(int a, int b) {
a = 5;
cout << "1: " << a << b; // prints 1: 5,6
}
a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b; // prints 2: 0,6
Or the const version:
// Passes in const references a and b.
int doSomething(const int &a, const int &b) {
a = 5; // COMPILE ERROR, cannot assign to const reference.
cout << "1: " << b; // prints 1: 6
}
a = 0;
b = 6;
doSomething(a, b);
References are used to pass locations of variables, so they don't need to be copied on the stack to the new function.
A simple pair of examples which you can run online.
The first uses a normal function, and the second uses references:
Example 1 (no reference)
Example 2 (reference)
Edit - here's the source code incase you don't like links:
Example 1
using namespace std;
void foo(int y){
y=2;
}
int main(){
int x=1;
foo(x);
cout<<x;//outputs 1
}
Example 2
using namespace std;
void foo(int & y){
y=2;
}
int main(){
int x=1;
foo(x);
cout<<x;//outputs 2
}
I don't know if this is the most basic, but here goes...
typedef int Element;
typedef std::list<Element> ElementList;
// Defined elsewhere.
bool CanReadElement(void);
Element ReadSingleElement(void);
int ReadElementsIntoList(int count, ElementList& elems)
{
int elemsRead = 0;
while(elemsRead < count && CanReadElement())
elems.push_back(ReadSingleElement());
return count;
}
Here we use a reference to pass our list of elements into ReadElementsIntoList(). This way, the function loads the elements right into the list. If we didn't use a reference, then elems would be a copy of the passed-in list, which would have the elements added to it, but then elems would be discarded when the function returns.
This works both ways. In the case of count, we don't make it a reference, because we don't want to modify the count passed in, instead returning the number of elements read. This allows the calling code to compare the number of elements actually read to the requested number; if they don't match, then CanReadElement() must have returned false, and immediately trying to read some more would likely fail. If they match, then maybe count was less than the number of elements available, and a further read would be appropriate. Finally, if ReadElementsIntoList() needed to modify count internally, it could do so without mucking up the caller.
How about by metaphor: Say your function counts beans in a jar. It needs the jar of beans and you need to know the result which can't be the return value (for any number of reasons). You could send it the jar and the variable value, but you'll never know if or what it changes the value to. Instead, you need to send it that variable via a return addressed envelope, so it can put the value in that and know it's written the result to the value at said address.
Correct me if I'm wrong, but a reference is only a dereferenced pointer, or?
The difference to a pointer is, that you can't easily commit a NULL.
I wrote a simple piece of C++ code to pass addresses by reference.
I am passing the address of a variable (say y) and an array (say arr) to a class. Both arr and y will get modified inside the class. I want to have the modified values in my main().
Please find my question in the below piece of code as it is easier that way. Thanks.
#include <iostream>
using namespace std;
class A
{
public:
// Assign values to the array and increment _x.
void increment()
{
(*_x)++;
(*_arr)[0] = 1; // Q1. Is it safe to directly access the array like this.
(*_arr)[1] = 2; // Don't I have to allocate memory to the array ?
(*_arr)[2] = 3;
}
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
*_arr = arr;
}
private:
int* _x;
int** _arr;
};
int main()
{
int y = 9;
int arr[5];
int *pY = &y;
int *pArr = arr;
A *obj1 = new A(pArr, pY);
// This gives a compile time error. warning: initialization of non-const reference int *&' from rvalue `int *'
// A *obj1 = new A(&y); <-- Q2. Why does this give a Compile Time Error ?
obj1->increment();
cout << "y : " << y << endl;
cout << "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << endl;
cout << endl;
return 0;
}
In A::increment() function, I am directly assigning values to the array without
allocating memory. Is it safe to do ? If not, how can I allocate memory so that
I can still get the modified array values in main() ?
Why do I get a compile time error whey I pass &y to A's constructor ?
Thanks in advance.
Question 1
In A::increment() function, I am directly assigning values to the array without allocating memory. Is it safe to do ? If not, how can I allocate memory so that I can still get the modified array values in main() ?
Answer
Yes, it is safe.
Question 2
Why do I get a compile time error whey I pass &y to A's constructor ?
Answer
&y is not an lvalue. Hence, it cannot be used where the argument type is int*&.
Problem in posted code
*_arr = arr;
That is a problem since _arr has not been initialized to point to a valid memory. Using *_arr when _arr has not been initialized causes undefined behavior. You can change the type of _arr to:
int* _arr;
and simplify your code a little bit.
class A
{
public:
// Assign values to the array and increment _x.
void increment()
{
(*_x)++;
_arr[0] = 1; // Q1. Is it safe to directly access the array like this.
_arr[1] = 2; // Don't I have to allocate memory to the array ?
_arr[2] = 3;
}
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x),
_arr(arr)
{
}
private:
int* _x;
int* _arr;
};
without changing anything in main.
This is very rarely what you want; a T** is generally an array of arrays or else a pointer value that you want to modify in the caller’s scope. However, neither seems to be what you’re doing here.
It is safe to modify *_arr[0] if and only if _arr has been initialized to a array of non-const arrays, and (*_arr)[0] if and only if it has been initialized as a pointer to a non-const array. Neither appears to be the case here, but if it is, you probably want to give the array length explicitly.
In this example, &y is a constant. You can’t modify it, so you can’t pass it as a non-const variable. You can declare a pointer int *py = &y; and pass that. But consider whether that’s what you want to do.
By the way, it’s not good style to use identifiers that start with underscores, because by the standard, they’re reserved for the compiler to use.
You should tell us what you are trying to do. In my opinion it's nonsense using raw pointers/arrays and naked new/(missing?) delete in C++ without good reason. I would also like to note that it is not considered good practice using the _prefix for class members. Usually leading _ are used for std implementations. I recommend using m_prefix if you insist on one. And why do you give _arr the type int**? Is is supposed to be a 2D-Array? Additionally, it doesn't really make sense passing a pointer by reference. A pointer is already a pointer, if you know what I mean, just pass the pointer around.
I'm just going to assume that you are doing this to understand manual memory management or pointer arithmetics or - wait, right: Tell us what you are trying to do and why. Nevertheless, I don't understand what you have the class for:
#include <iostream>
void increment(int& x, int *arr, int sz)
{
++x;
for (int i = 0; i != sz; ++i)
{
// this just numbers the values respectively (starting at 1)
arr[i] = i + 1;
}
}
int main()
{
using namespace std;
int y = 9;
const int sz = 5;
int arr[sz];
increment(y, arr, sz);
cout << "y : " << y << '\n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "\n\n";
}
To answer your questions:
2. First thing first: I don't see any constructor that only takes one argument.
Read up on "Undefined Behaviour (UB)" starting point: What are all the common undefined behaviours that a C++ programmer should know about?
I can't repeat enough that I don't understand what you are going for and that makes it hard to give solid advice.
I tried fixing your version.. well its still terrible... I highly recommend on reading up on std::array, std::vector. Maybe on pointers, C-Style Arrays and how to pass C-Style Arrays as function arguments (note: for regular C++ programming you wouldn't be doing/using that, usually).
#include <iostream>
class A {
public:
// Assign values to the array and increment m_x.
void increment()
{
++(*m_x);
m_arr[0] = 1;
m_arr[1] = 2;
m_arr[2] = 3;
}
A (int* arr, int* x):
m_x(x), m_arr(arr)
{
}
private:
int* m_x;
int* m_arr;
};
int main()
{
using namespace std;
int y = 9;
int arr[5];
A obj1(arr, &y);
obj1.increment();
cout << "y : " << y << '\n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "\n\n";
A obj2(arr, &y);
obj2.increment();
cout << "y : " << y << '\n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "\n\n";
}
You should also read up un pointers/references and their differences
I am actually trying to make your programming life easier. Sorry for long answer.
In answer to your first question
In A::increment() function, I am directly assigning values to the
array without allocating memory. Is it safe to do ? If not, how can I
allocate memory so that I can still get the modified array values in
main() ?
you allocated memory in main(), in the line
int arr[5];
In terms of class design, you defined your class constructor to accept reference arguments, which means that an existing int* must be passed to each argument:
A (int* &arr, int* &x)
and you do so when you invoke the constructor:
A *obj1 = new A(pArr, pY);
so in this program, what you are doing is safe. A potential danger if you expect to use this class in another context would be if your arr array in main() contained fewer than 3 elements, since your increment() function initializes the third element of the array.
In answer to your second question
Why do I get a compile time error whey I pass &y to A's constructor ?
In your original constructor,
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
*_arr = arr;
}
you are dereferencing _arr before it has been initialized. One way to solve this would be to do this:
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
_arr = new (int*);
*_arr = arr;
}
// Destructor
~A ()
{
delete _arr;
}
As an aside, you also use new in main(). Whenever you use new, you should also use delete to avoid a memory leak. So at the bottom of your program, before the return statement, add the following:
delete obj1;
I found these symbols in a function declaration several times, but I don't know what they mean.
Example:
void raccogli_dati(double **& V, double **p, int N) {
int ultimo = 3;
V = new double * [N/2];
for(int i=0; i < N/2; i++) {
V[i] = new double[N/2], std :: clog << "digita " << N/2 - i
<< " valori per la parte superiore della matrice V: ";
for(int j=i; j < N/2; j++)
std :: cin >> V[i][j], p[ultimo++][0] = (V[i][j] /= sqrt(p[i][0]*p[j][0]));
}
for(int i=1; i < N/2; i++)
for(int j=0; j < i; j++)
V[i][j] = V[j][i];
}
That is taking the parameter by reference. So in the first case you are taking a pointer parameter by reference so whatever modification you do to the value of the pointer is reflected outside the function. Second is the simlilar to first one with the only difference being that it is a double pointer. See this example:
void pass_by_value(int* p)
{
//Allocate memory for int and store the address in p
p = new int;
}
void pass_by_reference(int*& p)
{
p = new int;
}
int main()
{
int* p1 = NULL;
int* p2 = NULL;
pass_by_value(p1); //p1 will still be NULL after this call
pass_by_reference(p2); //p2 's value is changed to point to the newly allocate memory
return 0;
}
First is a reference to a pointer, second is a reference to a pointer to a pointer. See also FAQ on how pointers and references differ.
void foo(int*& x, int**& y) {
// modifying x or y here will modify a or b in main
}
int main() {
int val = 42;
int *a = &val;
int **b = &a;
foo(a, b);
return 0;
}
That's passing a pointer by reference rather than by value. This for example allows altering the pointer (not the pointed-to object) in the function is such way that the calling code sees the change.
Compare:
void nochange( int* pointer ) //passed by value
{
pointer++; // change will be discarded once function returns
}
void change( int*& pointer ) //passed by reference
{
pointer++; // change will persist when function returns
}
An int* is a pointer to an int, so int*& must be a reference to a pointer to an int. Similarly, int** is a pointer to a pointer to an int, so int**& must be a reference to a pointer to a pointer to an int.
*& signifies the receiving the pointer by reference. It means it is an alias for the passing parameter. So, it affects the passing parameter.
#include <iostream>
using namespace std;
void foo(int *ptr)
{
ptr = new int(50); // Modifying the pointer to point to a different location
cout << "In foo:\t" << *ptr << "\n";
delete ptr ;
}
void bar(int *& ptr)
{
ptr = new int(80); // Modifying the pointer to point to a different location
cout << "In bar:\t" << *ptr << "\n";
// Deleting the pointer will result the actual passed parameter dangling
}
int main()
{
int temp = 100 ;
int *p = &temp ;
cout << "Before foo:\t" << *p << "\n";
foo(p) ;
cout << "After foo:\t" << *p << "\n";
cout << "Before bar:\t" << *p << "\n";
bar(p) ;
cout << "After bar:\t" << *p << "\n";
delete p;
return 0;
}
Output:
Before foo: 100
In foo: 50
After foo: 100
Before bar: 100
In bar: 80
After bar: 80
Typically, you can read the declaration of the variable from right to left. Therefore in the case of int *ptr; , it means that you have a Pointer * to an Integer variable int. Also when it's declared int **ptr2;, it is a Pointer variable * to a Pointer variable * pointing to an Integer variable int , which is the same as "(int *)* ptr2;"
Now, following the syntax by declaring int*& rPtr;, we say it's a Reference & to a Pointer * that points to a variable of type int. Finally, you can apply again this approach also for int**& rPtr2; concluding that it signifies a Reference & to a Pointer * to a Pointer * to an Integer int.
To understand those phrases let's look at the couple of things:
typedef double Foo;
void fooFunc(Foo &_bar){ ... }
So that's passing a double by reference.
typedef double* Foo;
void fooFunc(Foo &_bar){ ... }
now it's passing a pointer to a double by reference.
typedef double** Foo;
void fooFunc(Foo &_bar){ ... }
Finally, it's passing a pointer to a pointer to a double by reference. If you think in terms of typedefs like this you'll understand the proper ordering of the & and * plus what it means.
This *& in theory as well as in practical its possible and called as reference to pointer variable. and it's act like same.
This *& combination is used in as function parameter for 'pass by' type defining. unlike ** can also be used for declaring a double pointer variable.
The passing of parameter is divided into pass by value, pass by reference, pass by pointer.
there are various answer about "pass by" types available. however the basic we require to understand for this topic is.
pass by reference --> generally operates on already created variable refereed while passing to function e.g fun(int &a);
pass by pointer --> Operates on already initialized 'pointer variable/variable address' passing to function e.g fun(int* a);
auto addControl = [](SomeLabel** label, SomeControl** control) {
*label = new SomeLabel;
*control = new SomeControl;
// few more operation further.
};
addControl(&m_label1,&m_control1);
addControl(&m_label2,&m_control2);
addControl(&m_label3,&m_control3);
in the above example(this is the real life problem i came across) i am trying to init few pointer variable from the lambda function and for that we need to pass it by double pointer, so that comes with d-referencing of pointer for its all usage inside of that lambda + while passing pointer in function which takes double pointer, you need to pass reference to the pointer variable.
so with this same thing reference to the pointer variable, *& this combination helps. in below given way for the same example i have mentioned above.
auto addControl = [](SomeLabel*& label, SomeControl*& control) {
label = new SomeLabel;
control = new SomeControl;
// few more operation further.
};
addControl(m_label1,m_control1);
addControl(m_label2,m_control2);
addControl(m_label3,m_control3);
so here you can see that you neither require d-referencing nor we require to pass reference to pointer variable while passing in function, as current pass by type is already reference to pointer.
Hope this helps :-)
I am trying to understand how to use reference parameters. There are several examples in my text, however they are too complicated for me to understand why and how to use them.
How and why would you want to use a reference? What would happen if you didn't make the parameter a reference, but instead left the & off?
For example, what's the difference between these functions:
int doSomething(int& a, int& b);
int doSomething(int a, int b);
I understand that reference variables are used in order to change a formal->reference, which then allows a two-way exchange of parameters. However, that is the extent of my knowledge, and a more concrete example would be of much help.
Think of a reference as an alias. When you invoke something on a reference, you're really invoking it on the object to which the reference refers.
int i;
int& j = i; // j is an alias to i
j = 5; // same as i = 5
When it comes to functions, consider:
void foo(int i)
{
i = 5;
}
Above, int i is a value and the argument passed is passed by value. That means if we say:
int x = 2;
foo(x);
i will be a copy of x. Thus setting i to 5 has no effect on x, because it's the copy of x being changed. However, if we make i a reference:
void foo(int& i) // i is an alias for a variable
{
i = 5;
}
Then saying foo(x) no longer makes a copy of x; i is x. So if we say foo(x), inside the function i = 5; is exactly the same as x = 5;, and x changes.
Hopefully that clarifies a bit.
Why is this important? When you program, you never want to copy and paste code. You want to make a function that does one task and it does it well. Whenever that task needs to be performed, you use that function.
So let's say we want to swap two variables. That looks something like this:
int x, y;
// swap:
int temp = x; // store the value of x
x = y; // make x equal to y
y = temp; // make y equal to the old value of x
Okay, great. We want to make this a function, because: swap(x, y); is much easier to read. So, let's try this:
void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
This won't work! The problem is that this is swapping copies of two variables. That is:
int a, b;
swap(a, b); // hm, x and y are copies of a and b...a and b remain unchanged
In C, where references do not exist, the solution was to pass the address of these variables; that is, use pointers*:
void swap(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int a, b;
swap(&a, &b);
This works well. However, it's a bit clumsy to use, and actually a bit unsafe. swap(nullptr, nullptr), swaps two nothings and dereferences null pointers...undefined behavior! Fixable with some checks:
void swap(int* x, int* y)
{
if (x == nullptr || y == nullptr)
return; // one is null; this is a meaningless operation
int temp = *x;
*x = *y;
*y = temp;
}
But looks how clumsy our code has gotten. C++ introduces references to solve this problem. If we can just alias a variable, we get the code we were looking for:
void swap(int& x, int& y)
{
int temp = x;
x = y;
y = temp;
}
int a, b;
swap(a, b); // inside, x and y are really a and b
Both easy to use, and safe. (We can't accidentally pass in a null, there are no null references.) This works because the swap happening inside the function is really happening on the variables being aliased outside the function.
(Note, never write a swap function. :) One already exists in the header <algorithm>, and it's templated to work with any type.)
Another use is to remove that copy that happens when you call a function. Consider we have a data type that's very big. Copying this object takes a lot of time, and we'd like to avoid that:
struct big_data
{ char data[9999999]; }; // big!
void do_something(big_data data);
big_data d;
do_something(d); // ouch, making a copy of all that data :<
However, all we really need is an alias to the variable, so let's indicate that. (Again, back in C we'd pass the address of our big data type, solving the copying problem but introducing clumsiness.):
void do_something(big_data& data);
big_data d;
do_something(d); // no copies at all! data aliases d within the function
This is why you'll hear it said you should pass things by reference all the time, unless they are primitive types. (Because internally passing an alias is probably done with a pointer, like in C. For small objects it's just faster to make the copy then worry about pointers.)
Keep in mind you should be const-correct. This means if your function doesn't modify the parameter, mark it as const. If do_something above only looked at but didn't change data, we'd mark it as const:
void do_something(const big_data& data); // alias a big_data, and don't change it
We avoid the copy and we say "hey, we won't be modifying this." This has other side effects (with things like temporary variables), but you shouldn't worry about that now.
In contrast, our swap function cannot be const, because we are indeed modifying the aliases.
Hope this clarifies some more.
*Rough pointers tutorial:
A pointer is a variable that holds the address of another variable. For example:
int i; // normal int
int* p; // points to an integer (is not an integer!)
p = &i; // &i means "address of i". p is pointing to i
*p = 2; // *p means "dereference p". that is, this goes to the int
// pointed to by p (i), and sets it to 2.
So, if you've seen the pointer-version swap function, we pass the address of the variables we want to swap, and then we do the swap, dereferencing to get and set values.
Lets take a simple example of a function named increment which increments its argument. Consider:
void increment(int input) {
input++;
}
which will not work as the change takes place on the copy of the argument passed to the function on the actual parameter. So
int i = 1;
std::cout<<i<<" ";
increment(i);
std::cout<<i<<" ";
will produce 1 1 as output.
To make the function work on the actual parameter passed we pass its reference to the function as:
void increment(int &input) { // note the &
input++;
}
the change made to input inside the function is actually being made to the actual parameter. This will produce the expected output of 1 2
GMan's answer gives you the lowdown on references. I just wanted to show you a very basic function that must use references: swap, which swaps two variables. Here it is for ints (as you requested):
// changes to a & b hold when the function exits
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
// changes to a & b are local to swap_noref and will go away when the function exits
void swap_noref(int a, int b) {
int tmp = a;
a = b;
b = tmp;
}
// changes swap_ptr makes to the variables pointed to by pa & pb
// are visible outside swap_ptr, but changes to pa and pb won't be visible
void swap_ptr(int *pa, int *pb) {
int tmp = *pa;
*pa = *pb;
*pb = tmp;
}
int main() {
int x = 17;
int y = 42;
// next line will print "x: 17; y: 42"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap can alter x & y
swap(x,y);
// next line will print "x: 42; y: 17"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap_noref can't alter x or y
swap_noref(x,y);
// next line will print "x: 42; y: 17"
std::cout << "x: " << x << "; y: " << y << std::endl
// swap_ptr can alter x & y
swap_ptr(&x,&y);
// next line will print "x: 17; y: 42"
std::cout << "x: " << x << "; y: " << y << std::endl
}
There is a cleverer swap implementation for ints that doesn't need a temporary. However, here I care more about clear than clever.
Without references (or pointers), swap_noref cannot alter the variables passed to it, which means it simply cannot work. swap_ptr can alter variables, but it uses pointers, which are messy (when references won't quite cut it, however, pointers can do the job). swap is the simplest overall.
On Pointers
Pointers let you do some of the same things as references. However, pointers put more responsibility on the programmer to manage them and the memory they point to (a topic called "memory management"–but don't worry about it for now). As a consequence, references should be your preferred tool for now.
Think of variables as names bound to boxes that store a value. Constants are names bound directly to values. Both map names to values, but the value of constants can't be changed. While the value held in a box can change, the binding of name to box can't, which is why a reference cannot be changed to refer to a different variable.
Two basic operations on variables are getting the current value (done simply by using the variable's name) and assigning a new value (the assignment operator, '='). Values are stored in memory (the box holding a value is simply a contiguous region of memory). For example,
int a = 17;
results in something like (note: in the following, "foo # 0xDEADBEEF" stands for a variable with name "foo" stored at address "0xDEADBEEF". Memory addresses have been made up):
____
a # 0x1000: | 17 |
----
Everything stored in memory has a starting address, so there's one more operation: get the address of the value ("&" is the address-of operator). A pointer is a variable that stores an address.
int *pa = &a;
results in:
______ ____
pa # 0x10A0: |0x1000| ------> # 0x1000: | 17 |
------ ----
Note that a pointer simply stores a memory address, so it doesn't have access to the name of what it points to. In fact, pointers can point to things without names, but that's a topic for another day.
There are a few operations on pointers. You can dereference a pointer (the "*" operator), which gives you the data the pointer points to. Dereferencing is the opposite of getting the address: *&a is the same box as a, &*pa is the same value as pa, and *pa is the same box as a. In particular, pa in the example holds 0x1000; * pa means "the int in memory at location pa", or "the int in memory at location 0x1000". "a" is also "the int at memory location 0x1000". Other operation on pointers are addition and subtraction, but that's also a topic for another day.
// Passes in mutable references of a and b.
int doSomething(int& a, int& b) {
a = 5;
cout << "1: " << a << b; // prints 1: 5,6
}
a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b; // prints 2: 5,6
Alternatively,
// Passes in copied values of a and b.
int doSomething(int a, int b) {
a = 5;
cout << "1: " << a << b; // prints 1: 5,6
}
a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b; // prints 2: 0,6
Or the const version:
// Passes in const references a and b.
int doSomething(const int &a, const int &b) {
a = 5; // COMPILE ERROR, cannot assign to const reference.
cout << "1: " << b; // prints 1: 6
}
a = 0;
b = 6;
doSomething(a, b);
References are used to pass locations of variables, so they don't need to be copied on the stack to the new function.
A simple pair of examples which you can run online.
The first uses a normal function, and the second uses references:
Example 1 (no reference)
Example 2 (reference)
Edit - here's the source code incase you don't like links:
Example 1
using namespace std;
void foo(int y){
y=2;
}
int main(){
int x=1;
foo(x);
cout<<x;//outputs 1
}
Example 2
using namespace std;
void foo(int & y){
y=2;
}
int main(){
int x=1;
foo(x);
cout<<x;//outputs 2
}
I don't know if this is the most basic, but here goes...
typedef int Element;
typedef std::list<Element> ElementList;
// Defined elsewhere.
bool CanReadElement(void);
Element ReadSingleElement(void);
int ReadElementsIntoList(int count, ElementList& elems)
{
int elemsRead = 0;
while(elemsRead < count && CanReadElement())
elems.push_back(ReadSingleElement());
return count;
}
Here we use a reference to pass our list of elements into ReadElementsIntoList(). This way, the function loads the elements right into the list. If we didn't use a reference, then elems would be a copy of the passed-in list, which would have the elements added to it, but then elems would be discarded when the function returns.
This works both ways. In the case of count, we don't make it a reference, because we don't want to modify the count passed in, instead returning the number of elements read. This allows the calling code to compare the number of elements actually read to the requested number; if they don't match, then CanReadElement() must have returned false, and immediately trying to read some more would likely fail. If they match, then maybe count was less than the number of elements available, and a further read would be appropriate. Finally, if ReadElementsIntoList() needed to modify count internally, it could do so without mucking up the caller.
How about by metaphor: Say your function counts beans in a jar. It needs the jar of beans and you need to know the result which can't be the return value (for any number of reasons). You could send it the jar and the variable value, but you'll never know if or what it changes the value to. Instead, you need to send it that variable via a return addressed envelope, so it can put the value in that and know it's written the result to the value at said address.
Correct me if I'm wrong, but a reference is only a dereferenced pointer, or?
The difference to a pointer is, that you can't easily commit a NULL.