I'm coding in C++. If I have some function void foo(vector<int> test) and I call it in my program, will the vector be passed by value or reference? I'm unsure because I know vectors and arrays are similar and that a function like void bar(int test[]) would pass test in by reference (pointer?) instead of by value. My guess is that I would need to pass the vector by pointer/reference explicitly if I wanted to avoid passing by value but I'm not sure.
In C++, things are passed by value unless you specify otherwise using the &-operator (note that this operator is also used as the 'address-of' operator, but in a different context). This is all well documented, but I'll re-iterate anyway:
void foo(vector<int> bar); // by value
void foo(vector<int> &bar); // by reference (non-const, so modifiable inside foo)
void foo(vector<int> const &bar); // by const-reference
You can also choose to pass a pointer to a vector (void foo(vector<int> *bar)), but unless you know what you're doing and you feel that this is really is the way to go, don't do this.
Also, vectors are not the same as arrays! Internally, the vector keeps track of an array of which it handles the memory management for you, but so do many other STL containers. You can't pass a vector to a function expecting a pointer or array or vice versa (you can get access to (pointer to) the underlying array and use this though). Vectors are classes offering a lot of functionality through its member-functions, whereas pointers and arrays are built-in types. Also, vectors are dynamically allocated (which means that the size may be determined and changed at runtime) whereas the C-style arrays are statically allocated (its size is constant and must be known at compile-time), limiting their use.
I suggest you read some more about C++ in general (specifically array decay), and then have a look at the following program which illustrates the difference between arrays and pointers:
void foo1(int *arr) { cout << sizeof(arr) << '\n'; }
void foo2(int arr[]) { cout << sizeof(arr) << '\n'; }
void foo3(int arr[10]) { cout << sizeof(arr) << '\n'; }
void foo4(int (&arr)[10]) { cout << sizeof(arr) << '\n'; }
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
foo1(arr);
foo2(arr);
foo3(arr);
foo4(arr);
}
A vector is functionally same as an array. But, to the language vector is a type, and int is also a type. To a function argument, an array of any type (including vector[]) is treated as pointer. A vector<int> is not same as int[] (to the compiler). vector<int> is non-array, non-reference, and non-pointer - it is being passed by value, and hence it will call copy-constructor.
So, you must use vector<int>& (preferably with const, if function isn't modifying it) to pass it as a reference.
void foo(vector<int> test)
vector would be passed by value in this.
You have more ways to pass vectors depending on the context:-
1) Pass by reference:- This will let function foo change your contents of the vector. More efficient than pass by value as copying of vector is avoided.
2) Pass by const-reference:- This is efficient as well as reliable when you don't want function to change the contents of the vector.
when we pass vector by value in a function as an argument,it simply creates the copy of vector and no any effect happens on the vector which is defined in main function when we call that particular function.
while when we pass vector by reference whatever is written in that particular function,
every action will going to perform on the vector which is defined in main or other function when we call that particular function.
Related
I'm learning c ++ And the syntax of putting a std::array into the function confuses me.
#include <iostream>
#include <array>
using namespace std;
void printArray(const std::array<int, 5> &n)
{
std::cout << "length: " << n.size() << endl;
for (int j = 0; j < n.size(); j++ )
{
cout << "n[" << j << "] = " << n[j] << endl;
}
}
int main()
{
array<int, 5> n = {1,2,3,4,5};
printArray(n);
return 0;
}
I want to ask about 'const', what role does it play and what effect does it have if not using it?
Why do we have to use &n while the name of an array is already pointer
Depending on the argument you can do certain assumptions about the function.
void printArrayA(std::array<int, 5> n)
If I call printArrayA then the array I pass to it is copied, so the function can't do changes to the array I pass, but has an overhead of copying the array.
void printArrayB(std::array<int, 5> &n)
If I call printArrayB then the array I pass to it is not copied, the function could do changes on the array, or on the elements stored in the array.
void printArrayC(const std::array<int, 5> &n)
If I call printArrayC then the array I pass to it is not copied, and because it is const the function can't do any changes on that array or on its elements. (Well I, in theory, could cast away the const, but that's not something that should be done, a const should indicate the caller, that the object won't be changed)
void printArray(const std::array<int, 5> &n)
What this does is to allow you to pass in to the function an unchangeable (without const-casting it, anyway) reference to the std::array. The reference is a lot smaller than the array itself, typically just a pointer, and the const bit ensures the function does not attempt to change the underlying object.
It's usually used to ensure you don't copy "large" things where unnecessary, things like vectors, arrays or strings.
In this case const means that printArray will not modify the object passed to it.
An std::array is not a C-style array (such ase int a[10]), so you are not passing a pointer, you are passing a reference to an std::array object.
Your question is not only about 'std::vector', it is about 'const' and 'references'.
'const' keywords means that you can call only 'const' method of that class, means that (assume that the used class is implemented correctly) you can't modify this class in that method.
'&' means that you pass the parameter by 'reference' and not by 'value', if you are not familiar with that difference you may want to read this: Value vs. Reference
As others have mentioned, the name of a std::array does not decay to a pointer. To convert to a pointer, you would call .data().
Why do you want to pass by (const) reference, and why does a foo[]decay to a foo* const in many contexts?
You (practically) never want to copy arrays. It takes a huge amount of time and memory. You always want to pass them to a function by reference. On top of that, most algorithms that work on arrays are supposed to work on arrays of any size. (Brian Kernighan, the K in K&R, particularly considered it a flaw in Pascal that the size of an array is part of its type.) Therefore, back in the ’70s, the designers of C made a rule that passing an array to a function is the same as passing a pointer to its first element.
C++ stuck with that for the sake of backward compatibility: a lot of programmers compile C code in C++ compilers. One famous pitfall is trying to take the sizeof an array parameter in C++. Because array parameters decay to pointers, this gives you the size of a pointer. In C++, you have the option of passing a type (&name)[size] instead; that is, passing a type[size] by reference. This preserves the size as part of the type. (C also got some new syntax in 1999 that never made it over to C++, including the ability to pass the size of an array parameter.)
In C++, a std::array has no special syntax and works like any other type. You never want to copy an entire array that you aren’t going to modify. You still want to pass arrays by reference, so you use the standard syntax for that: &. Whenever you don’t need to modify a parameter, you declare it const. This helps the compiler detect logic errors and, sometimes, optimize.
I'm coding in C++. If I have some function void foo(vector<int> test) and I call it in my program, will the vector be passed by value or reference? I'm unsure because I know vectors and arrays are similar and that a function like void bar(int test[]) would pass test in by reference (pointer?) instead of by value. My guess is that I would need to pass the vector by pointer/reference explicitly if I wanted to avoid passing by value but I'm not sure.
In C++, things are passed by value unless you specify otherwise using the &-operator (note that this operator is also used as the 'address-of' operator, but in a different context). This is all well documented, but I'll re-iterate anyway:
void foo(vector<int> bar); // by value
void foo(vector<int> &bar); // by reference (non-const, so modifiable inside foo)
void foo(vector<int> const &bar); // by const-reference
You can also choose to pass a pointer to a vector (void foo(vector<int> *bar)), but unless you know what you're doing and you feel that this is really is the way to go, don't do this.
Also, vectors are not the same as arrays! Internally, the vector keeps track of an array of which it handles the memory management for you, but so do many other STL containers. You can't pass a vector to a function expecting a pointer or array or vice versa (you can get access to (pointer to) the underlying array and use this though). Vectors are classes offering a lot of functionality through its member-functions, whereas pointers and arrays are built-in types. Also, vectors are dynamically allocated (which means that the size may be determined and changed at runtime) whereas the C-style arrays are statically allocated (its size is constant and must be known at compile-time), limiting their use.
I suggest you read some more about C++ in general (specifically array decay), and then have a look at the following program which illustrates the difference between arrays and pointers:
void foo1(int *arr) { cout << sizeof(arr) << '\n'; }
void foo2(int arr[]) { cout << sizeof(arr) << '\n'; }
void foo3(int arr[10]) { cout << sizeof(arr) << '\n'; }
void foo4(int (&arr)[10]) { cout << sizeof(arr) << '\n'; }
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
foo1(arr);
foo2(arr);
foo3(arr);
foo4(arr);
}
A vector is functionally same as an array. But, to the language vector is a type, and int is also a type. To a function argument, an array of any type (including vector[]) is treated as pointer. A vector<int> is not same as int[] (to the compiler). vector<int> is non-array, non-reference, and non-pointer - it is being passed by value, and hence it will call copy-constructor.
So, you must use vector<int>& (preferably with const, if function isn't modifying it) to pass it as a reference.
void foo(vector<int> test)
vector would be passed by value in this.
You have more ways to pass vectors depending on the context:-
1) Pass by reference:- This will let function foo change your contents of the vector. More efficient than pass by value as copying of vector is avoided.
2) Pass by const-reference:- This is efficient as well as reliable when you don't want function to change the contents of the vector.
when we pass vector by value in a function as an argument,it simply creates the copy of vector and no any effect happens on the vector which is defined in main function when we call that particular function.
while when we pass vector by reference whatever is written in that particular function,
every action will going to perform on the vector which is defined in main or other function when we call that particular function.
I understand the implicit conversion into a pointer. Someone suggested something like this today in some other question:
#include <iostream>
void printArray(int (&a)[5]) {
for (int i : a) {
std::cout << i << " ";
}
}
int main() {
int a[] = { 1, 2, 3, 4, 5 };
printArray(a);
}
Questions
Is this the only and the best way of passing an entire array to a function rather than just the pointer to the first element (though inefficient)?
However, if that function were to be written below the main function, what would the function prototype be?
Also, if I were to only use an enhanced for loop to iterate through the elements of an array passed to a function, is there any better way?
1) This does not pass the entire array to the function. It passes a reference to the array. Since the compiler knows the type of the argument, it is able to do appropriate checks (when calling the function) and access array elements (within the function).
2) The declaration of the function (as opposed to the definition/implementation) would be;
void printArray(int (&a)[5]);
The name of the parameter (a) is optional in this.
3) Since printing an object (including an array) does not typically change the object, it would be appropriate for the argument of printArray() to be const-qualified. This also allows the caller to pass a const array (which is not possible in the code as shown). Furthermore, the type of i used in the loop can also be a const reference (which avoids copying elements of the array by value). It would also be possible to use automatic type inference (i.e. auto). Increased const-safety is often viewed as beneficial (since it increases chances of picking up attempts to modify something that should not be changed).
I'm coding in C++. If I have some function void foo(vector<int> test) and I call it in my program, will the vector be passed by value or reference? I'm unsure because I know vectors and arrays are similar and that a function like void bar(int test[]) would pass test in by reference (pointer?) instead of by value. My guess is that I would need to pass the vector by pointer/reference explicitly if I wanted to avoid passing by value but I'm not sure.
In C++, things are passed by value unless you specify otherwise using the &-operator (note that this operator is also used as the 'address-of' operator, but in a different context). This is all well documented, but I'll re-iterate anyway:
void foo(vector<int> bar); // by value
void foo(vector<int> &bar); // by reference (non-const, so modifiable inside foo)
void foo(vector<int> const &bar); // by const-reference
You can also choose to pass a pointer to a vector (void foo(vector<int> *bar)), but unless you know what you're doing and you feel that this is really is the way to go, don't do this.
Also, vectors are not the same as arrays! Internally, the vector keeps track of an array of which it handles the memory management for you, but so do many other STL containers. You can't pass a vector to a function expecting a pointer or array or vice versa (you can get access to (pointer to) the underlying array and use this though). Vectors are classes offering a lot of functionality through its member-functions, whereas pointers and arrays are built-in types. Also, vectors are dynamically allocated (which means that the size may be determined and changed at runtime) whereas the C-style arrays are statically allocated (its size is constant and must be known at compile-time), limiting their use.
I suggest you read some more about C++ in general (specifically array decay), and then have a look at the following program which illustrates the difference between arrays and pointers:
void foo1(int *arr) { cout << sizeof(arr) << '\n'; }
void foo2(int arr[]) { cout << sizeof(arr) << '\n'; }
void foo3(int arr[10]) { cout << sizeof(arr) << '\n'; }
void foo4(int (&arr)[10]) { cout << sizeof(arr) << '\n'; }
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
foo1(arr);
foo2(arr);
foo3(arr);
foo4(arr);
}
A vector is functionally same as an array. But, to the language vector is a type, and int is also a type. To a function argument, an array of any type (including vector[]) is treated as pointer. A vector<int> is not same as int[] (to the compiler). vector<int> is non-array, non-reference, and non-pointer - it is being passed by value, and hence it will call copy-constructor.
So, you must use vector<int>& (preferably with const, if function isn't modifying it) to pass it as a reference.
void foo(vector<int> test)
vector would be passed by value in this.
You have more ways to pass vectors depending on the context:-
1) Pass by reference:- This will let function foo change your contents of the vector. More efficient than pass by value as copying of vector is avoided.
2) Pass by const-reference:- This is efficient as well as reliable when you don't want function to change the contents of the vector.
when we pass vector by value in a function as an argument,it simply creates the copy of vector and no any effect happens on the vector which is defined in main function when we call that particular function.
while when we pass vector by reference whatever is written in that particular function,
every action will going to perform on the vector which is defined in main or other function when we call that particular function.
I recently found some code like this:
typedef int TenInts[10];
void foo(TenInts &arr);
What can you do in the body of foo() that is useful, that you could not do if the declaration was:
void foo(int *arr); // or,
void foo(int arr[]); // or,
void foo(int arr[10]); // ?
I found a question that asks how to pass a reference to an array. I guess I am asking why.
Also, only one answer to "When is pointer to array useful?" discussed function parameters, so I don't think this is a duplicate question.
The reference-to-array parameter does not allow array type to decay to pointer type. i.e. the exact array type remains preserved inside the function. (For example, you can use the sizeof arr / sizeof *arr trick on the parameter and get the element count). The compiler will also perform type checking in order to make sure the array argument type is exactly the same as the array parameter type, i.e. if the parameter is declared as a array of 10 ints, the argument is required to be an array of exactly 10 ints and nothing else.
In fact, in situations when the array size is fixed at compile-time, using a reference-to-array (or pointer-to-array) parameter declarations can be preceived as the primary, preferred way to pass an array. The other variant (when the array type is allowed to decay to pointer type) are reserved for situations when it is necessary to pass arrays of run-time size.
For example, the correct way to pass an array of compile-time size to a function is
void foo(int (&arr)[10]); // reference to an array
or
void foo(int (*arr)[10]); // pointer to an array
An arguably incorrect way would be to use a "decayed" approach
void foo(int arr[]); // pointer to an element
// Bad practice!!!
The "decayed" approach should be normally reserved for arrays of run-time size and is normally accompanied by the actual size of the array in a separate parameter
void foo(int arr[], unsigned n); // pointer to an element
// Passing a run-time sized array
In other words, there's really no "why" question when it comes to reference-to-array (or pointer-to-array) passing. You are supposed to use this method naturally, by default, whenever you can, if the array size is fixed at compile-time. The "why" question should really arise when you use the "decayed" method of array passing. The "decayed" method is only supposed to be used as a specialized trick for passing arrays of run-time size.
The above is basically a direct consequence of a more generic principle. When you have a "heavy" object of type T, you normally pass it either by pointer T * or by reference T &. Arrays are no exception from this general principle. They have no reason to be.
Keep in mind though that in practice it is often makes sense to write functions that work with arrays of run-time size, especially when it comes to generic, library-level functions. Such functions are more versatile. That means that often there's a good reason to use the "decayed" approach in real life code, Nevertheless, this does not excuse the author of the code from recognizing the situations when the array size is known at compile time and using the reference-to-array method accordingly.
One difference is that it's (supposed to be) impossible to pass a null reference. So in theory the function does not need to check if the parameter is null, whereas an int *arr parameter could be passed null.
You can write a function template to find out the size of an array at compile time.
template<class E, size_t size>
size_t array_size(E(&)[size])
{
return size;
}
int main()
{
int test[] = {2, 3, 5, 7, 11, 13, 17, 19};
std::cout << array_size(test) << std::endl; // prints 8
}
No more sizeof(test) / sizeof(test[0]) for me ;-)
Shouldn't we also address the words in bold from the question:
What can you do in the body of foo() that is useful, that you could not do if the declaration was void foo(int arr[]);?
The answer is: nothing. Passing an argument by reference allows a function to change its value and pass back this change to the caller. However, it is not possible to change the value of the array as a whole, which would have been a reason to pass it by reference.
void foo(int (&arr)[3]) { // reference to an array
arr = {1, 2 ,3}; // ILLEGAL: array type int[3] is not assignable
arr = new(int[3]); // same issue
arr = arr2; // same issue, with arr2 global variable of type int[3]
}
You can ensure that the function is only called on int arrays of size 10. That may be useful from a type-checking standpoint.
You get more semantic meaning regarding what the function is expecting.