Pointer Constants#
int *const ptr = nullptr;
The const
keyword modifies the value of the pointer ptr
, and ptr
itself cannot be modified. Therefore, a pointer constant must be initialized, and we cannot modify the value of ptr
.
int a = 10;
int *const ptr = &a;
ptr = nullptr; // error
Applications of Pointer Constants#
For example, we need to write a function that swaps the values of two integers using pointer parameters.
Here is the implementation code:
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
The above code can achieve the desired functionality, but it has a problem. We can modify the value pointed to by the pointer within the function body, and we can also modify the value of the pointer itself (which is not what we want). To make the code more robust, we can use pointer constants to ensure that the value passed to the pointer is not unintentionally modified.
Here is the modified code:
void swap(int *const a, int *const b) { ... }
Constant Pointers#
const int *ptr;
// or
int const *ptr;
The const
keyword modifies the value of *ptr
, which is the value pointed to by the pointer. The value pointed to by ptr
is not modifiable. Without performing a constant type conversion, we cannot modify *ptr
.
int a = 10;
int const *ptr = &a;
*ptr = 20; // error
Applications of Constant Pointers#
For example, we need to write a function that prints an array.
Here is the implementation code:
void printArray(int const* arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
std::cout << arr[i] << " ";
}
}
You might think that using const
to modify the value pointed to by the pointer derived from the array is sufficient. However, there is still a problem because we can still modify the value of the pointer within the function body, which is not what we want. Therefore, on top of that, we need to use const
to modify the value of the pointer.
Here is the modified code:
void printArray(int const *const arr, size_t len) { ... }
Relationship between Pointer Constants and Constant Pointers#
We can see that there are two ways to write constant pointers: int const *
and const int *
.
For the understanding of the first form: const
is modifying to the left, for example: int const *ptr;
The const
keyword modifies the value type int
, so the value pointed to by the pointer cannot be modified. int *const ptr = nullptr;
The const
keyword modifies the pointer type int *
, so the pointer cannot be modified. This understanding needs to follow the code convention because if the constant pointer is written as const int *
, we need to perform a conversion. (It can also be understood as if there is no object on the left, it is converted to modify the object on the right.)
The naming of constant pointers and pointer constants corresponds to the code convention of const int *
and int *const
.
Observe the following code:
#include <iostream>
struct A {
void foo() { std::cout << "non const" << std::endl; }
void foo() const { std::cout << "const" << std::endl; }
};
int main() {
A a;
A *const ptr1 = &a;
ptr1->foo();
A const *ptr2 = &a;
ptr2->foo();
}
In int *const ptr1 = &a
, the const
keyword modifies the value of the pointer ptr1
and does not modify the object pointed to by the pointer. Therefore, ptr1->foo()
calls the non-const
version.
In int const *ptr2 = &a
, the const
keyword modifies the value pointed to by the pointer ptr2
, meaning that the value pointed to cannot be modified. Therefore, ptr2->foo()
calls the const
version.
If there are any omissions, please let me know.