指针常量#
int *const ptr = nullptr;
const
修饰的是指针 ptr
的值,ptr
本身不能被修改,所以指针常量必须初始化,同时我们无法对 ptr
的值进行修改。
int a = 10;
int *const ptr = &a;
ptr = nullptr; // error
指针常量的应用场景#
例如:需要编写一个函数,实现使用传参指针的形式交换两个整形的值。
下面是实现代码:
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
上述代码可以实现功能,但是存在一定的问题,因为我们可以在函数体内可以修改指针的所指向的值,同时也可以修改指针的值(这并不是我们所希望的),为了使代码更为健壮,我们可以使用指针常量,使得传入指针的值不会被无意修改。
下面是修改后的代码:
void swap(int *const a, int *const b) { ... }
常量指针#
const int *ptr;
// 或
int const *ptr;
const
修饰的 *ptr
的值,也就是指针所指向的值,ptr
指向的值是不可修改的。同时在不进行常量类型转换的情况下我们无法对 *ptr
进行修改。
int a = 10;
int const *ptr = &a;
*ptr = 20; // error
常量指针的应用场景#
例如:需要编写一个函数,实现打印一个数组。
下面是实现代码:
void printArray(int const* arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
std::cout << arr[i] << " ";
}
}
这里你可能会认为使用 const
修饰数组退化而来的指针所指向的值就可以了,但是这仍存在的问题,因为我们仍可以在函数体内修改指针的值,这并不是我们希望的,因此在此基础上还需要 const
修饰指针的值。
下面是修改后的代码:
void printArray(int const *const arr, size_t len) { ... }
指针常量与常量指针的关系#
我们会发现常量指针有两种写法:int const *
和 const int *
。
对于第一种形式的理解:const
是向左修饰的,例如:int const *ptr;
中 const
修饰的是 int
值类型,所以指针指向的值不可以修改;int *const ptr = nullptr;
中 const
修饰 int *
指针类型,所以指针指向不能修改。这种理解需要遵守的代码规范,因为如果将常量指针写成 const int *
就需要我们进行转换了。(也可以理解为如果左侧没有对象,则转为修饰右侧对象。)
常量指针和指针常量的命名则是与 const int *
和 int *const
的代码规范相对应。
观察以下代码:
#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();
}
int *const ptr1 = &a
中 const
修饰的是 ptr1
指针的值,没有修饰指针所指向的对象,所以 ptr1->foo()
调用非 const
版本。
int const *ptr2 = &a
中 const
修饰的是 ptr2
指针指向的值 a
,意思是指向的值不可修改,所以 ptr2->foo()
调用 const
版本。
如有纰漏,欢迎指正。