Reputation: 7802
I understand that a const pointer can be declared a couple ways:
const int * intPtr1; // Declares a pointer that cannot be changed.
int * const intPtr2; // Declares a pointer whose contents cannot be changed.
// EDIT: THE ABOVE CLAIMS ARE INCORRECT, PLEASE READ THE ANSWERS.
But what about the same principles within the context of function arguments?
I would assume that the following is redundant:
void someFunc1(const int * arg);
void someFunc2(int * arg);
Since someFunc 1 and 2 do a pass-by-value for the pointer itself, its impossible for someFunc1 to change the value of the original pointer, in a given call to the function. To illustrate:
int i = 5;
int * iPtr = &i;
someFunc1(iPtr); // The value of iPtr is copied in and thus cannot be changed by someFunc1.
If these are true, then there is no point in ever declaring a function with a 'const int * ptr' type arg, correct?
Upvotes: 24
Views: 40222
Reputation: 9590
Well it is not meant for the caller but for the code inside the someFunc1
. So that any code inside someFunc1
wont accidentally change it. like
void someFunc1(int *arg) {
int i = 9;
arg = &i; // here is the issue
int j = *arg;
}
Lets do some case study:
1) Just making the pointed value const
void someFunc1(const int * arg) {
int i = 9;
*arg = i; // <- compiler error as pointed value is const
}
2) Just making the pointer const
void someFunc1(int * const arg) {
int i = 9;
arg = &i; // <- compiler error as pointer is const
}
3) Right way to use const if variables involved can be const:
void someFunc1(const int * const arg) {
int i = 9;
*arg = i; // <- compiler error as pointed value is const
arg = &i; // <- compiler error as pointer is const
}
This should clear all doubts. So I already mentioned it is meant for the function code and not for the caller and you should use the most restrictive of the 3 cases i mentioned above.
EDIT:
const
. This will not only increase readability but also the caller will be aware of the contract and has more confidence regarding immutability of arguments. (This is required bcoz you generally share your header files so caller might not have your implementation c/cpp file)Upvotes: 28
Reputation: 20211
You have it the wrong way:
const int * intPtr1; // Declares a pointer whose contents cannot be changed.
int * const intPtr2; // Declares a pointer that cannot be changed.
Generally speaking its easier to reason about constness when writting that expression slightly different: const int*
is the same type as int const *
. In that notation the rules are much clearer, const
always applies to the type preceding it, therefore:
int const * intPtr1; // Declares a pointer to const int.
int * const intPtr2; // Declares a const pointer to int.
int const * * const * complexPtr; // A pointer to const pointer to pointer to const int
When the type is written with a leading const
, the const
is handled as if it was written after the first type, so const T*
becomes T const *
.
void someFunc2(int * arg);
Is therefore not redundant, since someFunc2
may change the contents of arg
, while someFunc1
may not. void someFunc3(int * const arg);
would be redundant (and ambigous) though
Upvotes: 2
Reputation: 34912
You've got your logic the wrong way round. You should read the type backwards, so const int *
is a pointer to a const int
and int * const
is a const
pointer to an int.
Example:
void foo() {
int a = 0;
int b = 0;
int * const ptrA = &a;
*ptrA = 1;
ptrA = &b; ///< Error
const int * ptrB = &a;
*ptrB = 1; ///< Error
ptrB = &b;
const int * const ptrC = &a;
*ptrC = 1; ///< Error
ptrC = &a; ///< Error
}
To elaborate and show why you would want your function parameter to be a const int *
you might want to indicate to the caller that they must pass in an int
because you as a function want to change the value. Consider this code for instance:
void someFunc1(const int * arg) {
// Can't change *arg in here
}
void someFunc2(int * arg) {
*arg = 5;
}
void foo() {
int a = 0;
someFunc1(&a);
someFunc2(&a);
const int b = 0;
someFunc1(&b);
someFunc2(&b); ///< *** Error here. Must pass in an int not a const int.
}
Upvotes: 7
Reputation: 254751
You have it backwards:
const int * intPtr1; // Declares a pointer whose contents cannot be changed.
int * const intPtr2; // Declares a pointer that cannot be changed.
The following const
is indeed unnecessary, and there's no reason to put it in a function declaration:
void someFunc1(int * const arg);
However, you might want to put it in the function implementation, for the same reason that you might want to declare a local variable (or anything else) const
- the implementation may be easier to follow when you know that certain things won't change. You can do that whether or not it's declared const
in any other declarations of the function.
Upvotes: 40
Reputation: 147056
Yes, you are correct (ignoring the fact that you got them the wrong way around)- there is no sense in taking non-reference const
parameters. In addition, there is no sense in returning non-reference const
values.
Upvotes: 2